2012-01-07 20 views
13

Noté que itertools no (me parece) tiene una función capaz de elementos de intercalado de varios otros objetos iterables (en contraposición a comprimirlos):¿Python tiene una función incorporada para entrelazar generadores/secuencias?

def leaf(*args): return (it.next() for it in cycle(imap(chain,args))) 
tuple(leaf(['Johann', 'Sebastian', 'Bach'], repeat(' '))) => ('Johann', ' ', 'Sebastian', ' ', 'Bach', ' ') 

(Edit) La razón que pido es porque Quiero evitar las apariciones zip/flatten innecesarias.

Obviamente, la definición de leaf es bastante simple, pero si hay una función predefinida que hace lo mismo, preferiría usar eso, o una expresión de generador muy clara. ¿Existe tal función incorporada, en itertools, o en alguna otra biblioteca bien conocida, o una expresión idiomática adecuada?

Edición 2: Una definición más concisa es posible (utilizando el paquete functional):

from itertools import * 
from functional import * 

compose_mult = partial(reduce, compose) 
leaf = compose_mult((partial(imap, next), cycle, partial(imap, chain), lambda *args: args)) 
+6

En una nota totalmente no relacionada, no puedo dejar de mencionar que el Bach en cuestión era Johann, no John. – 9000

+0

@ 9000: Bastante - esto cayó de una prueba unitaria donde lo escribí distraídamente ya que es – Marcin

Respuesta

4

Los itertools roundrobin() recipe habrían sido mi primera opción, aunque en su ejemplo exacta que produciría una secuencia infinita, ya que se detiene con el iterable más larga, no el mas corto Por supuesto, sería fácil arreglar eso. Tal vez vale la pena echarle un vistazo para un enfoque diferente?

+0

Ese es el tipo de cosas que estaba pensando, excepto que (a) prefiero la semántica de la hoja (b) mi definición es más concisa. – Marcin

9

Usted está buscando la incorporada en zip y itertools.chain.from_iterable para aplanar el resultado:

>>> import itertools 
>>> list(zip(['Johann', 'Sebastian', 'Bach'], itertools.repeat(' '))) 
[('Johann', ' '), ('Sebastian', ' '), ('Bach', ' ')] 
>>> list(itertools.chain.from_iterable(_)) 
['Johann', ' ', 'Sebastian', ' ', 'Bach', ' '] 

Tenga en cuenta que utilicé list solo para forzar una buena salida. El uso de los itertools estándar, implementaciones alternativas para leaf serían:

leaf = lambda *a: itertools.chain.from_iterable(itertools.izip(*a)) # Python 2.x 
leaf = lambda *a: itertools.chain.from_iterable(zip(*a))   # Python 3.x 
+0

¿No sería 'izip' más seguro? –

+0

@larsmans ¿Más seguro de qué manera? 'itertools.izip' ha sido eliminado de Python desde 3.0. – phihag

+1

Bien. Todavía vivo en el mundo de Python 2.x principalmente. –

Cuestiones relacionadas