在Python中优雅快速地连续遍历两个或多个容器的方法?

40 投票
10 回答
27906 浏览
提问于 2025-04-16 10:35

我有三个集合(collection.deques),我需要做的是遍历这三个集合,并对每个集合执行相同的操作:

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中已经有这样的东西吗,还是我需要自己写一个函数呢?

10 个回答

9

你可能觉得我有点疯狂,但为什么大家觉得用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里某个东西的文档。

21

答案在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
55

根据你想要处理这些项目的顺序:

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
>>>

撰写回答