2012-07-16 16 views
8

desidero sapere come scrivere funzione pitone che può appiattire generatore che produce altri generatori o iteables (che può anche produrre altri generatori/iterables ... possibilmente all'infinito).Python: Funzione per appiattire generatore contenente un altro generatore

Ecco esempio:

gen(gen(1,2,3), gen(4,5,6), [7,8,9], [gen(10,11,12), gen(13,14,15)])

nota: gen - mezzi oggetto generatore, contenuto tra parentesi dopo gen è dati che generatore gen resa.

Il risultato atteso dopo "appiattimento": gen(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)

È necessario che la funzione di appiattire per tornare generatore di troppo! (altrimenti, l'uso precedente dei generatori sarebbe privo di significato).

Solo per notare, io sto usando Python 3.

Grazie!

risposta

12

Il modo più semplice è una funzione ricorsiva appiattimento. Supponendo che si vuole scendere in ogni iterabile tranne per le stringhe, si potrebbe fare questo:

def flatten(it): 
    for x in it: 
     if (isinstance(x, collections.Iterable) and 
      not isinstance(x, str)): 
      for y in flatten(x): 
       yield y 
     else: 
      yield x 

A partire da Python 3.3, è possibile anche scrivere

def flatten(it): 
    for x in it: 
     if (isinstance(x, collections.Iterable) and 
      not isinstance(x, str)): 
      yield from flatten(x) 
     else: 
      yield x 
+0

Grazie mille! Con il mio tentativo ero molto vicino al tuo :-) Saluti! – JoshuaBoshi

+0

+1 - Continuo a dimenticare "yield from" e questo è stato un bel promemoria. –

+2

@JonClements: È "Continuo a dimenticare" le caratteristiche di una versione di Python wich non è stato nemmeno ancora rilasciato? Sono sorpreso. :) –

0

Il metodo non ricorsivo è essenzialmente uno srotolamento di il metodo ricorsivo, usando una pila:

def flatten(it): 
    stack = [] 
    it = iter(it) 
    while True: 
     try: 
      x = next(it) 
     except StopIteration: 
      if stack: 
       it = stack.pop() 
       continue 
      else: 
       return 
     if isinstance(x, collections.Iterable) and not isinstance(x, str): 
      stack.append(it) 
      it = iter(x) 
     else: 
      yield x