优化python代码 - 分析和更改列表

时间:2016-08-16 08:51:09

标签: python-2.7

作为输入,我有这样的列表(项目数量可能会改变):

b = [0.1, 1, 5, 8, 0.4, 2, 0.3, 0.4, 1, 2, 2, 3, 4, 5, 0.1]

如果列表中的两个下一个项是int和float,则插入到列表字符串" X"之后就像那样:

[0.1, 1, 5, 8, 'X', 0.4, 2, 'X', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'X', 0.1]

这是我的代码,第一部分检查满足此条件的项目数量,第二部分添加' X'。

c = 0
for i in range(len(b)):
    if type(b[i]) == float and type(b[i-1]) == int:
        c += 1
st = 0      
while st < c:
    for i in range(len(b)):
        if type(b[i]) == float and type(b[i-1]) == int:
            b.insert(i, "X")
            continue
    st += 1
print b

问题是如何优化此代码?

这是一些解决方案,但在这里我基于b列表的长度正在改变 - 糟糕的解决方案。

while True:
    for i in range(0, len(b)):
        if type(b[i]) == float and type(b[i-1]) == int:
            b.insert(i, "ok")
            continue
    break
print b

2 个答案:

答案 0 :(得分:2)

您可以使用以下命令找到正确的插入索引:

indexes = [i for i, pair in enumerate(zip(b, b[1:])) if isinstance(pair[0], int) and isinstance(pair[1], float)]

zip()只是创建一对相邻值。

[(0.1, 1), (1, 5), (5, 8), (8, 0.4), (0.4, 2), (2, 0.3), (0.3, 0.4), (0.4, 1), (1, 2), (2, 2), (2, 3), (3, 4), (4, 5), (5, 0.1)]

枚举将跟踪索引处的索引和值。您可以使用该值将类型与isinstance进行比较,并仅保留与您的过滤器匹配的索引。

对于您的示例,这将返回[3, 5, 13]。但是,您不能简单地按顺序插入这些位置,因为索引会发生变化。

所以,你可以:

  1. 遍历索引并将下一个索引增加1,然后增加2,等等[3, 6, 15]
  2. 反向插入,首先插入13,然后插入5,然后插入3.
  3. >>> for i in indexes[::-1]:
    ...     b.insert(i+1, 'ok')
    ...
    >>> b
    [0.1, 1, 5, 8, 'ok', 0.4, 2, 'ok', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'ok', 0.1]
    

答案 1 :(得分:1)

你可以使用generator function一次性完成,每次我们得到一个匹配时设置一个标志,所以我们只生成一次相同的对象:

b = [0.1, 1, 5, 8, 0.4, 2, 0.3, 0.4, 1, 2, 2, 3, 4, 5, 0.1]

def insert_x(lst):
    # create iterator
    it = iter(lst)
    # set matched to False initial and prev to the first element.
    prev, matched = next(it), False
    # start loop from second element.
    for ele in it:
        if isinstance(prev,  int) and isinstance(ele, float):
            yield prev
            yield "X"
            yield ele
            matched = True
        elif not matched:
            yield prev
        else:
            matched = False
        prev = ele

演示:

In [10]: b = [0.1, 1, 5, 8, 0.4, 2, 0.3, 0.4, 1, 2, 2, 3, 4, 5, 0.1]

In [11]: b[:] = insert_x(b)

In [12]: b
Out[12]: [0.1, 1, 5, 8, 'X', 0.4, 2, 'X', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'X', 0.1]

进行插入是很昂贵的,有些时间:

In [12]: b
Out[12]: [0.1, 1, 5, 8, 'X', 0.4, 2, 'X', 0.3, 0.4, 1, 2, 2, 3, 4, 5, 'X', 0.1]

In [13]: from random import choice

In [14]: b = [choice(b) for _ in range(100000)]

In [15]: timeit list(insert_x(b))
10 loops, best of 3: 91.2 ms per loop

In [16]: %%timeit
   ....: indexes = [i for i, pair in enumerate(zip(b, b[1:])) if isinstance(pair[0], int) and isinstance(pair[1], float)]
   ....: c = b[:]
   ....: for i in indexes[::-1]:
   ....:     c.insert(i+1, 'ok')
   ....: 
1 loop, best of 3: 1.5 s per loop

In [17]: timeit b[:]
1000 loops, best of 3: 895 µs per loop

In [6]: indexes = [i for i, pair in enumerate(zip(b, b[1:])) if isinstance(pair[0], int) and isinstance(pair[1], float)]

In [7]: c = b[:] 
In [8]: for i in indexes[::-1]:
   ...:         c.insert(i+1, 'X')
   ...:     

In [9]: c == list(insert_x(b)) # exact same result.
Out[9]: True

如果你拿走c = b[:]的费用,它仍然会明显变慢。差不多1.5秒vs 91ms。