2010-03-18 4 views
5
def flattenList(toFlatten): 
final=[] 
for el in toFlatten: 
    if isinstance(el, list): 
    final.extend(flattenList(el)) 
    else: 
    final.append(el) 
return final 

Quando non so quanto profondamente le liste si annidano, questo è l'unico modo in cui posso pensare di farlo.Esiste un modo funzionale per farlo?

+0

Prova a utilizzare quattro spazi anziché uno per il rientro. È più leggibile e si conformerà alle linee guida di stile utilizzate per la maggior parte del codice Python. (La guida di stile cui la maggior parte del codice Python è conforme è http://www.python.org/dev/peps/pep-0008/) –

+0

Domande correlate: "Flatten (un elenco irregolare) di elenchi in Python" http: // stackoverflow .com/questions/2158395/flatten-an-irregular-list-of-lists-in-python (link ad altre domande e buone risposte) "Appiattire una lista poco profonda in python" http://stackoverflow.com/questions/406121/flattening-a-shallow-list-in-python (benchmark) – jfs

risposta

2

Ecco un'altra opzione (se ci possono essere qualcosa di più pulito di tipo controllo, come il test se qualcosa è iterabile e quindi non un "atomo"):

def flatten(lst): 
    if not isinstance(lst,list): 
     return [lst] 
    else: 
     return reduce(lambda x,y:x+y,[flatten(x) for x in lst],[]) 

Si basa su qualcosa di schema simile.

+1

'prova: return reduce (...); tranne TypeError: return [lst] ' – Debilski

+0

Questo è perfetto.Grazie – Ishpeck

+0

@mitmatt, 1) La funzione' lambda x, y: x + y' è chiamata 'operator.add'. 2) Il tuo algoritmo è così inutilmente O (n * m) ish, quando l'algoritmo lineare è più ovvio. –

7
  1. Si dovrebbe evitare il typechecking in Python. In questo caso, ciò significa evitare strutture nidificate arbitrariamente dove si distingue per tipo. Puoi creare il tuo tipo di nodo che puoi percorrere con i metodi altro rispetto a typechecking, come guardare un attributo specifico.

  2. Per appiattire un livello o esattamente n livelli, vedere itertools.chain.from_iterable.

  3. Non so cosa intendi per "funzionale". Questo codice è piuttosto funzionale: usa la ricorsione (non al suo merito!) E non modifica la sua argomentazione. (A rigor di termini, si fa uso di stato mutevole per la costruzione di una lista, ma che è proprio come lo si fa in Python.

  4. Suppongo che un attributo più funzionale sarebbe la valutazione pigra. Si potrebbe implementare questa convenzione è

    def flatten(toFlatten): 
        for item in toFlatten: 
         if isinstance(item, list): # Ewww, typchecking 
          for subitem in flatten(item): # they are considering adding 
           yield subitem    # "yield from" to the language 
                  # to give this pattern syntax 
         else: 
          yield item 
    
  5. La ricorsione è molto limitata in Python (almeno, in tutte le sue principali implementazioni) e generalmente dovrebbe essere evitata per profondità arbitrarie.È abbastanza possibile riscrivere questo (e tutto il codice ricorsivo) per usare l'iterazione, che renderà questo più scalabile (e meno funzionale, che è una buona cosa in Python, che non è particolarmente adatto per FP.)

+0

@Mike Graham: voglio essere in grado di passare in elenchi contenenti elenchi contenenti elenchi, contenenti elenchi, ecc. e appiattirli fino a un solo risultato. Voglio: [1,2, [3,4,5,6], 7,8, [9,10, [11,12, [13, [14,15], 16], 17], 20 ]] Per uscire come: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 20] Se io Sapevamo in anticipo quanto profondamente annidate le liste, questo sarebbe sufficiente: def mergeLists (seq): \t return reduce (lambda x, y: x + y, seq) – Ishpeck

+0

1) Smettila di volerlo. Definisci la tua struttura in modo diverso. 2) La tua strategia 'reduce' è moltiplicativa nell'ordine big-O; gli algoritmi lineari sono ovvi. –

+0

Una risposta più generale: http://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists-in-python/2158532#2158532 – jfs

2

Sotto la doc per itertools, c'è una funzione di flatten()

+0

Non su quella pagina non c'è. –

+1

@Andrew Aylett, è una ricetta, non nel modulo stesso. È su quella pagina. –

+0

@Mike: ammettilo, hai modificato la documentazione dopo aver postato il mio commento. Non so come mi sia mancato - non è successo quando ho cercato la pagina al lavoro: P. –

3

Questa risposta spiega il motivo per cui non si desidera utilizzare reduce per questo in Python.

Si consideri il frammento di

reduce(operator.add, [[1], [2], [3], [4], [5]]) 

Che cosa ha a che fare?

[1] + [2] => [1, 2] 
[1, 2] + [3] => This makes a new list, having to go over 1, then 2, then 3. [1, 2, 3] 
[1, 2, 3] + [4] => This has to copy the 1, 2, and 3 and then put 4 in the new list 
[1, 2, 3, 4] + [5] => The length of stuff I have to copy gets bigger each time! 

Questo comportamento quadratico è completamente evitabile: la soluzione originale (e qualsiasi numero di altre soluzioni) non costituisce questi passaggi di copia intermedi.