Элегантный и быстрый способ последовательного перебора двух или более контейнеров в Python?
У меня есть три экземпляра 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 или мне нужно написать функцию для этого?
Ответы
Ответ 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.chain(deque1, deque2, deque3)
Ответ 4
Назовите меня сумасшедшим, но зачем использовать 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)
То, что происходит, сразу становится очевидным без необходимости просмотра кода/документов для функции long-name или поиска документов для itertools.something()
Ответ 5
Как насчет zip?
for obj in zip(deque1, deque2, deque3):
for sub_obj in obj:
some_action(sub_obj)
Ответ 6
Я бы просто сделал это:
for obj in deque1 + deque2 + deque3:
some_action(obj)
Ответ 7
Похоже, вы хотите, чтобы я tertools.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
Принимает кучу итераций и выводит содержимое для каждого из них в последовательности.
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