【问题标题】:Iterating over two lists one after another一个接一个地迭代两个列表
【发布时间】:2016-05-14 07:25:34
【问题描述】:

我有两个数字列表list1list2,我想用相同的指令对它们进行迭代。像这样:

for item in list1:
  print(item.amount)
  print(item.total_amount)

for item in list2:
  print(item.amount)
  print(item.total_amount)

但这感觉是多余的。我知道我可以写for item in list1 + list2:,但它的代价是运行时间。

有没有办法不浪费时间?

【问题讨论】:

    标签: python python-3.x list loops iteration


    【解决方案1】:

    这可以通过 itertools.chain 来完成:

    import itertools
    
    l1 = [1, 2, 3, 4]
    l2 = [5, 6, 7, 8]
    
    for i in itertools.chain(l1, l2):
        print(i, end=" ")
    

    将打印的内容:

    1 2 3 4 5 6 7 8 
    

    根据文档,chain 执行以下操作:

    创建一个迭代器,从第一个可迭代对象返回元素,直到它用完,然后继续下一个可迭代对象,直到所有可迭代对象都用完。

    如果您的列表包含在列表中,itertools.chain.from_iterable 可用:

    l = [l1, l2]
    for i in itertools.chain.from_iterable(l):
        print(i, end=" ")
    

    产生相同的结果。

    如果您不想为此导入模块,则为其编写函数非常简单:

    def custom_chain(*it):
        for iterab in it:
            yield from iterab
    

    这需要 Python 3,对于 Python 2,只需 yield 使用循环将它们返回:

    def custom_chain(*it):
        for iterab in it:
            for val in iterab:
                yield val
    

    除了前面的,Python 3.5 及其扩展的解包泛化,还允许在列表文字中解包:

    for i in [*l1, *l2]:
        print(i, end=" ")
    

    虽然这比l1 + l2 稍微快一点,但它仍然构造了一个列表,然后将其扔掉;仅将其作为最终解决方案。

    【讨论】:

    • 如果我在循环中添加 'if' 条件和 'break' 并且它将在第一个列表中触发,第二个将不会运行,对吗?
    【解决方案2】:

    chain 有效,但如果您觉得导入一个模块只是为了调用一个函数一次有点过头了,您可以内联复制它的行为:

    for seq in (list1, list2):
      for item in seq:
        print(item.amount)
        print(item.total_amount)
    

    创建 (list1, list2) 元组的列表长度为 O(1),因此与将列表连接在一起相比,它的性能应该更好。

    【讨论】:

      【解决方案3】:

      这个怎么样:

      for item in list1 + list2:
          print(item.amount)
          print(item.total_amount)
      

      只有 3 行

      【讨论】:

      • 我认为这会将列表连接到新创建的列表中,这会很昂贵。
      • 来自问题:“我知道我可以写for item in list1 + list2:
      【解决方案4】:

      经过多次处决,最快的选择是第二次。

      import itertools
      from time import time
      
      l1 = list(range(1000))
      l2 = list(range(1000))
      
      print('Alternative 1. Itertools')
      t = time()
      for j in range(10000):
          s = 0
          for i in itertools.chain(l1, l2):
              s += i
      print(time() - t)
      
      print('Alternative 2. Naive')
      t = time()
      for j in range(10000):
          s = 0
          for i in [*l1, *l2]:
              s += i
      print(time() - t)
      
      print('Alternative 3. Yield')
      def chain(*ls):
          for l in ls:
              for k in l:
                  yield k
      t = time()
      for j in range(10000):
          s = 0
          for i in chain(l1, l2):
              s += i
      print(time() - t)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-07
        • 1970-01-01
        • 2022-12-08
        • 2021-09-19
        • 1970-01-01
        • 1970-01-01
        • 2017-12-09
        • 2020-02-20
        相关资源
        最近更新 更多