2012-01-07 23 views
13

zauważyłem, że itertools nie robi (wydaje mi się) mają funkcję zdolną elementów przeplatania z kilkoma innymi iterowalny obiektów (w przeciwieństwie do kompresowania je):Czy python ma wbudowaną funkcję do przeplatania generatorów/sekwencji?

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

(Edit) Pytam o to dlatego, Chcę uniknąć niepotrzebnych zip/flatten wystąpień.

Oczywiście, definicja leaf jest dość prosta, ale jeśli istnieje predefiniowana funkcja, która robi to samo, wolałbym użyć tego lub bardzo przejrzystego wyrażenia generatora. Czy istnieje taka funkcja wbudowana w itertools lub w innej dobrze znanej bibliotece lub w odpowiednim idiomatycznym wyrażeniu?

Edit 2: Jeszcze bardziej zwięzła definicja jest możliwe (przy użyciu pakietu 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

W całkowicie niepowiązanej notatce nie mogę nie wspomnieć, że wspomniany Bach był Johann, a nie John. – 9000

+0

@ 9000: Całkiem - to wypadło z testu jednostkowego, w którym bezmyślnie napisałem go tak, jak jest – Marcin

Odpowiedz

4

W itertools roundrobin() recipe byłby już mój pierwszy wybór, choć w swoim dokładnym przykład byłoby produkować nieskończoną sekwencję, ponieważ zatrzymuje się przy najdłuższej iterable, nie najkrótszy. Oczywiście łatwo to naprawić. Może warto sprawdzić inne podejście?

+0

Tego rodzaju rzeczy myślałem, z wyjątkiem tego (a) Wolę semantykę liści (b) moja definicja jest bardziej zwięzła. – Marcin

9

szukasz wbudowanej zip i itertools.chain.from_iterable spłaszczyć Rezultat:

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

Zauważ, że użyłem list tylko po to, aby wymusić dobre wyjście. Używając standardowych itertools alternatywne implementacje dla leaf byłoby:

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

Czy "izip" nie byłby bezpieczniejszy? –

+0

@ larsmans Safer w jaki sposób? 'itertools.izip' został usunięty z Pythona od wersji 3.0. – phihag

+1

OK. Nadal mieszkam głównie w świecie Python 2.x. –

Powiązane problemy