【问题标题】:Iterate two lists in the same loop在同一个循环中迭代两个列表
【发布时间】:2016-04-07 05:56:42
【问题描述】:

如何在 Python 中遍历两个列表?我想要的结果正是

list1, list2, list3 = [0, 1], ['a', 'b'], [2, 3] # example data

for item in list1 + list2 + list3:
    print(item)

但我认为添加列表然后遍历它们效率不高。我使用for 循环遍历列表:

for list_ in (list1, list2, list3):
    for item in list_:
        print(item)

但是当我用timeit检查这个时,两者的执行时间非常相似。

有没有可能让它更快?

【问题讨论】:

标签: python list python-3.x for-loop time


【解决方案1】:

你可以试试内置的zip()函数。

>>> for m, n, k in zip([1,2,3,4,5], list('abcde'), [2,11,25,102,53]):
        print(m, n, k)


1 a 2
2 b 11
3 c 25
4 d 102
5 e 53

请注意,您可以将其他可迭代对象放入其中。

for m, n, k in zip(range(1,6), 'abcde', [2,11,25,102,53]):
    print(m, n, k)


1 a 2
2 b 11
3 c 25
4 d 102
5 e 53

【讨论】:

    【解决方案2】:

    如果您更喜欢数字,这里有一个测试用例,证明在迭代之前将列表加在一起是低效的。

    请注意,hugelists.py 包含三个列表,每个列表包含 10,000 个随机四位数字。

    from hugelists import list_one, list_two, list_three
    from itertools import chain
    from datetime import datetime
    
    def method_one():
        start_time = datetime.now()
        for item in list_one + list_two + list_three:
            pass
        stop_time = datetime.now()
        return stop_time - start_time
    
    def method_two():
        start_time = datetime.now()
        for item in chain(list_one, list_two, list_three):
            pass
        stop_time = datetime.now()
        return stop_time - start_time
    
    if __name__ == "__main__":
        print method_one()
        print method_two()
    

    结果:

    > python test.py
    0:00:00.001720
    0:00:00.001014
    > python test.py
    0:00:00.001865
    0:00:00.000997
    > python test.py
    0:00:00.001603
    0:00:00.000833
    

    【讨论】:

      【解决方案3】:

      您可以使用itertools 模块中的chain 方法将三个列表链接成一个:

      from itertools import chain:
      
      for item in chain(list1, list2, list3):
          print(item)
      

      或者:

      for item in chain.from_iterable([list1,list2,list3]):
          print(item)
      

      【讨论】:

        【解决方案4】:

        对于小型数据集,您不会发现太大差异。但通常如果你想链接和迭代多个迭代器,那么你可以使用itertools.chain,像这样

        >>> list1, list2, list3 = [0, 1], ['a', 'b'], [2, 3]
        >>> from itertools import chain
        >>> for item in chain(list1, list2, list3):
        ...     print(item)
        0
        1
        a
        b
        2
        3
        

        这不会创建任何中间数据结构并逐个迭代每个可迭代对象。 chain 返回的值是一个迭代器。所以这也不会创建一个包含所有项目的容器,并且如果迭代非常大,它会非常节省内存。

        itertools.chain 实际上与您的第二种方法相同。引用官方文档中的等效实现

        def chain(*iterables):
            # chain('ABC', 'DEF') --> A B C D E F
            for it in iterables:
                for element in it:
                    yield element
        

        如果我们查看为您展示的第一个程序生成的字节码,用这个

        from dis import dis
        list1, list2, list3 = [0, 1], ['a', 'b'], [2, 3]
        
        
        def func():
            for item in list1 + list2 + list3:
                print(item)
        
        dis(func)
        

        应该是这样的

          6           0 SETUP_LOOP              27 (to 30)
                      3 LOAD_GLOBAL              0 (list1)
                      6 LOAD_GLOBAL              1 (list2)
                      9 BINARY_ADD          
                     10 LOAD_GLOBAL              2 (list3)
                     13 BINARY_ADD          
                     14 GET_ITER            
                >>   15 FOR_ITER                11 (to 29)
                     18 STORE_FAST               0 (item)
        
          7          21 LOAD_FAST                0 (item)
                     24 PRINT_ITEM          
                     25 PRINT_NEWLINE       
                     26 JUMP_ABSOLUTE           15
                >>   29 POP_BLOCK           
                >>   30 LOAD_CONST               0 (None)
                     33 RETURN_VALUE        
        

        如您所见,BINARY_ADD 代码被使用了两次。这意味着首先添加list1list2,并创建一个临时列表,然后再次添加list3。如果任何列表非常大,这将非常低效。

        【讨论】:

          【解决方案5】:

          使用itertools.chain:

          for item in itertools.chain(list1, list2, list2):
              print(item)
          

          【讨论】:

            猜你喜欢
            • 2016-05-08
            • 1970-01-01
            • 2021-12-07
            • 2020-09-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-01-13
            相关资源
            最近更新 更多