2011-01-25 19 views
14

tengo tres collection.deques y lo que hay que hacer es iterar sobre cada uno de ellos y realizar la misma acción:¿Una manera elegante y rápida de iterar consecutivamente sobre dos o más contenedores en Python?

for obj in deque1: 
    some_action(obj) 

for obj in deque2: 
    some_action(obj) 

for obj in deque3: 
    some_action(obj) 

Busco alguna función XXX, que lo ideal sería permitir que escriba:

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

lo importante aquí es que XXX tiene que ser lo suficientemente eficiente - sin hacer copia o en silencio usando gama(), etc. me esperaba encontrar en las funciones integradas, pero no encontró nada similar a esta muy lejos.

¿Hay algo así en Python o tengo que escribir una función solo para eso?

+0

¿Has mirado la función zip? – Ikke

+0

AFAIK la función zip() no es lo que necesito aquí. – izhak

+0

El tema no tenía sentido para mí, así que cambié "en consecuencia" a "consecutivamente". Por favor retroceda si solo soy ignorante! –

Respuesta

19

Dependiendo de qué orden desea procesar los artículos:

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) 

yo recomiendo hacer esto para evitar la codificación dura de los deques, actuales o número de deques:

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

para demostrar la diferencia en el orden de los métodos anteriores:

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

La respuesta está en itertools

itertools.chain (* iterables)

Make an iterator that returns elements from the first iterable until 

que se agote, entonces procede a la siguiente iterable, hasta que todos los iterables se han agotado. Se usa para tratando secuencias consecutivas como una secuencia simple de . Equivalente a:

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

'itertools' not' iterutils' – FogleBird

+0

Gracias, actualizado. – Drakosha

2

¿Qué tal zip?

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

Uso itertools.chain(deque1, deque2, deque3)

0

acepta un manojo de iterables, y los rendimientos de los contenidos para cada uno de ellos en secuencia.

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 
1

Parece que desea i tertools.chain:

"hacer un iterador que devuelve los elementos de la primera iterables hasta que se agote, entonces procede a la siguiente iterable, hasta que todos los iterables se agotan. Se usa para tratar secuencias consecutivas como una secuencia única ".

1

Si entiendo su pregunta correctamente, puede usar map con el primer argumento establecido en Ninguno, y todos los demás argumentos como sus listas para iterar.

E.g (desde un símbolo IPython, pero se entiende la idea):

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

me llaman loco, pero ¿por qué está usando itertools se cree que son necesarias? ¿Qué pasa con:

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) 

Incluso más loco: es probable que va a utilizar esto una vez. ¿Por qué no acaba de hacer:

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

lo que está pasando allí es inmediatamente obvio, sin tener que mirar el código/docs para la función de nombre largo o tener que buscar los documentos de itertools.something()

+0

¿Por qué reinventar la rueda? Esto es algo que surge mucho. –

1

Simplemente haria esto:

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