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

Python 2.7 优化python代码-分析和更改列表,python-2.7,Python 2.7,作为输入,我得到了这样的列表(项目数量可能会发生变化): 若列表中接下来的两项是int和float,则在int之后插入列表字符串“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和float,则在int之后插入列表字符串“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

您可以通过以下内容找到正确的插入索引:

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,然后增加2,以此类推。生成
    [3,6,15]
  • 按相反的顺序插入,先插入13,然后插入5,然后插入3


  • 您可以在一次通过中使用,每次获得匹配时设置一个标志,以便只生成同一个对象一次:

    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 [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 91毫秒

    优化的具体原因是什么?我提出的第一个解决方案会在列表中迭代两次。是的,而你的第二个解决方案不会。那么为什么不使用它呢?这个问题不属于你SO@s_z_p:如果您只是将索引存储在一个附加列表中,然后按相反顺序迭代这些索引,并将其插入到b中,则可以使用第二种解决方案。你可以在我的答案的末尾看到它是如何工作的。另外,你不需要一个
    而True
    break
    。因为你使用的是
    2.7
    (根据标签),你可以使用
    itertools.izip
    而不是zip来避免创建额外的列表。@s_z_p,每次插入,你所做的不仅仅是插入一个,你正在改变所有的元素,这显然是非常昂贵的
    b[:]=insert_x(b)
    与您接受的答案中的insert逻辑相同,只是效率更高。@padraickenningham,写得不错,方法很棒。然而,我自己使用与您创建的相同的随机100000元素列表运行了相同的测试,并且我的方法在625-640ms内运行得非常一致。1.5秒是从哪里来的?@sberry,我实际上在那里又运行了一次,它的性能更差,使用python2和python3时,分别为~2.5秒和~100ms。您使用我的代码得到了什么时间?运行您的代码大约需要34-43毫秒,因此对于大型数据集(这是预期的)来说仍然要快一个数量级。我正在为py2使用jupyter控制台,并通过cmdline使用
    python-mtimeit-s“b=…”“我的代码在这里”和“这里”
    运行了我的控制台,收到了非常相似的结果,大约625ms。哈,没错。我认为你的时间是9毫秒,不是90毫秒。
    >>> 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]
    
    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