Элегантный и быстрый способ последовательной итерации по двум или более контейнерам в Python? - PullRequest
22 голосов
/ 25 января 2011

У меня есть три 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, или я должен написать функцию для этого сам?

Ответы [ 9 ]

33 голосов
/ 25 января 2011

В зависимости от того, какой заказ вы хотите обработать:

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
>>>
13 голосов
/ 25 января 2011

Ответ находится в 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
6 голосов
/ 26 января 2011

Назовите меня сумасшедшим, но почему использование 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 ()

5 голосов
/ 25 января 2011

Использование itertools.chain(deque1, deque2, deque3)

2 голосов
/ 01 сентября 2017

Я бы просто сделал это:

for obj in deque1 + deque2 + deque3:  
some_action(obj)  
2 голосов
/ 25 января 2011

Если я правильно понимаю ваш вопрос, то вы можете использовать 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 .
2 голосов
/ 25 января 2011

Как насчет почтового индекса?

for obj in zip(deque1, deque2, deque3):
    for sub_obj in obj:
        some_action(sub_obj)
1 голос
/ 25 января 2011

Похоже, вы хотите, я tertools.chain :

"Создайте итератор, который возвращает элементы из первой итерации до тех пор, пока она не будет исчерпана, затем переходит к следующей итерации, пока все итерации не будут исчерпаны. Используется для обработки последовательных последовательностей как одной последовательности."

0 голосов
/ 25 января 2011

Принимает несколько итераций и выдает содержимое для каждого из них в последовательности.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...