【问题标题】:An elegant and fast way to consecutively iterate over two or more containers in Python?在 Python 中连续迭代两个或多个容器的优雅而快速的方法?
【发布时间】:2011-06-15 07:27:25
【问题描述】:

我有三个 collection.deque,我需要做的是遍历它们并执行相同的操作:

for obj in deque1:  
    some_action(obj)  

for obj in deque2:  
    some_action(obj)

for obj in deque3:  
    some_action(obj)

我正在寻找一些功能 XXX 理想情况下可以让我编写:

for obj in XXX(deque1, deque2, deque3):  
    some_action(obj)

这里重要的是 XXX 必须足够高效 - 无需进行复制或静默使用 range() 等。我期待在内置函数中找到它,但到目前为止我没有发现任何类似的东西。

Python 中是否已经有这样的东西,或者我必须自己为此编写一个函数?

【问题讨论】:

  • 你看过zip函数吗?
  • AFAIK zip() 函数不是我需要的。
  • 这个主题对我来说没有意义,所以我将“consequently”改为“consecutively”。如果我只是无知,请回滚!
  • 谢谢,大卫,这确实有道理

标签: python iterator


【解决方案1】:

取决于您要处理的项目的顺序:

import itertools

for items in itertools.izip(deque1, deque2, deque3):
    for item in items:
        some_action(item)

for item in itertools.chain(deque1, deque2, deque3):
    some_action(item)

我建议这样做以避免硬编码实际的双端队列或双端队列数量:

deques = [deque1, deque2, deque3]
for item in itertools.chain(*deques):
    some_action(item)

为了演示上述方法的顺序不同:

>>> a = range(5)
>>> b = range(5)
>>> c = range(5)
>>> d = [a, b, c]
>>>
>>> for items in itertools.izip(*d):
...     for item in items:
...         print item,
...
0 0 0 1 1 1 2 2 2 3 3 3 4 4 4
>>>
>>> for item in itertools.chain(*d):
...     print item,
...
0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
>>>

【讨论】:

    【解决方案2】:

    答案在itertools

    itertools.chain(*iterables)
    

    创建一个迭代器,从第一个可迭代对象中返回元素,直到 它用尽了,然后继续 下一个可迭代的,直到所有 可迭代对象已用尽。用于 将连续序列视为 单序列。相当于:

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

    【讨论】:

      【解决方案3】:

      说我疯了,但为什么认为有必要使用 itertools?有什么问题:

      def perform_func_on_each_object_in_each_of_multiple_containers(func, containers):
          for container in containers:
              for obj in container:
                  func(obj)
      
      perform_func_on_each_object_in_each_of_multiple_containers(some_action, (deque1, deque2, deque3)
      

      更疯狂:你可能会使用一次。为什么不这样做:

      for d in (deque1, deque2, deque3):
          for obj in d:
              some_action(obj)
      

      无需查看长名称函数的代码/文档或查找 itertools.something() 的文档即可立即了解其中的情况

      【讨论】:

      • 为什么要重新发明轮子?这是经常出现的事情。
      【解决方案4】:

      使用itertools.chain(deque1, deque2, deque3)

      【讨论】:

        【解决方案5】:

        拉链怎么样?

        for obj in zip(deque1, deque2, deque3):
            for sub_obj in obj:
                some_action(sub_obj)
        

        【讨论】:

          【解决方案6】:

          接受一堆可迭代对象,并按顺序生成每个可迭代对象的内容。

          def XXX(*lists):
             for aList in lists:
                for item in aList:
                   yield item
          
          
          
          l1 = [1, 2, 3, 4]
          l2 = ['a', 'b', 'c']
          l3 = [1.0, 1.1, 1.2]
          
          for item in XXX(l1, l2, l3):
             print item
          
          1
          2
          3
          4
          a
          b
          c
          1.0
          1.1
          1.2
          

          【讨论】:

            【解决方案7】:

            看起来你想要 itertools.chain:

            “创建一个迭代器,它从第一个可迭代对象返回元素,直到它用完,然后继续到下一个可迭代对象,直到所有可迭代对象都用完。用于将连续序列视为单个序列。”

            【讨论】:

              【解决方案8】:

              如果我正确理解您的问题,那么您可以使用 map 并将第一个参数设置为 None,并将所有其他参数作为您的列表进行迭代。

              例如(来自 iPython 提示,但你明白了):

              In [85]: p = [1,2,3,4]
              
              In [86]: q = ['a','b','c','d']
              
              In [87]: f = ['Hi', 'there', 'world', '.']
              
              In [88]: for i,j,k in map(None, p,q,f):
                 ....:     print i,j,k
                 ....:
                 ....:
              1 a Hi
              2 b there
              3 c world
              4 d .
              

              【讨论】:

                【解决方案9】:

                我会这样做:

                for obj in deque1 + deque2 + deque3:  
                some_action(obj)  
                

                【讨论】:

                • 但是您将这些列表合并为一个超级列表。这是一个巨大的时间消耗。
                【解决方案10】:
                >>> a = [[],[],[]]
                >>> b = [[],[],[]]
                >>> for c in [*a,*b]:
                    c.append("derp")
                
                    
                >>> a
                [['derp'], ['derp'], ['derp']]
                >>> b
                [['derp'], ['derp'], ['derp']]
                >>> 
                

                【讨论】:

                • 请考虑为您的答案添加解释
                • 欢迎来到 Stack Overflow。虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。 How to Answer
                猜你喜欢
                • 2013-07-06
                • 1970-01-01
                • 2017-01-14
                • 2019-12-03
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多