Perché Python non ha una funzione "flatten" per le liste?

34

Erlang e Ruby sono entrambi dotati di funzioni per l'appiattimento degli array. Sembra uno strumento così semplice e utile da aggiungere a una lingua. Uno potrebbe fare questo:

>>> mess = [[1, [2]], 3, [[[4, 5]], 6]]
>>> mess.flatten()
[1, 2, 3, 4, 5, 6]

O anche:

>>> import itertools
>>> mess = [[1, [2]], 3, [[[4, 5]], 6]]
>>> list(itertools.flatten(mess))
[1, 2, 3, 4, 5, 6]

Invece, in Python, si deve passare attraverso il problema di scrivere una funzione per appiattire gli array da zero. Questo mi sembra sciocco, l'appiattimento degli array è una cosa così comune da fare. È come dover scrivere una funzione personalizzata per concatenare due array.

Ho cercato su Google questo inutilmente, quindi sto chiedendo qui; c'è un motivo particolare per cui un linguaggio maturo come Python 3, che include centinaia di migliaia di batterie incluse, non fornisce un metodo semplice per appiattire gli array? L'idea di includere tale funzione è stata discussa e rifiutata a un certo punto?

    
posta Hubro 24.08.2014 - 07:20
fonte

3 risposte

33

Le proposte per una funzione flatten da aggiungere alla libreria standard appaiono di volta in volta su python-dev e python-ideas mailing lists. Gli sviluppatori Python di solito rispondono con i seguenti punti:

  1. Un flatten a un livello (trasformando un iterabile di iterables in un singolo iterabile) è un'espressione banale di una riga (x for y in z for x in y) e in ogni caso è già nella libreria standard sotto il nome itertools.chain.from_iterable .

  2. Quali sono i casi d'uso per un appiattimento multilivello generico? Sono abbastanza avvincenti da consentire l'aggiunta della funzione alla libreria standard?

  3. In che modo un appiattimento multilivello di uso generale decide quando appiattirsi e quando lasciare da solo? Potresti pensare che una regola come "appiattisci tutto ciò che supporta l'interfaccia iterabile" funzionerebbe, ma ciò comporterebbe un ciclo infinito per flatten('a') .

Vedi ad esempio Raymond Hettinger :

It has been discussed ad nauseam on comp.lang.python. People seem to enjoy writing their own versions of flatten more than finding legitimate use cases that don't already have trivial solutions.

A general purpose flattener needs some way to be told what is atomic and what can be further subdivided. Also, it is not obvious how the algorithm should be extended to cover inputs with tree-like data structures with data at nodes as well as the leaves (preorder, postorder, inorder traversal, etc.)

    
risposta data 28.08.2014 - 14:40
fonte
8

Viene fornito con un tale metodo ma non lo chiama appiattito. Si chiama " catena ". Restituisce un iteratore per il quale è necessario utilizzare la funzione list () per tornare a un elenco. Se non si desidera utilizzare un *, è possibile utilizzare la seconda versione "from_iterator". Funziona stesso in Python 3. Fallirà se l'input dell'elenco non è un lista di liste.

[[1], [2, 3], [3, 4, 5]] #yes
[1, 2, [5, 6]] #no

C'era una volta un appiattimento metodo in il modulo compiler.ast ma questo è stato deprecato in 2.6 e poi rimosso in 3.0. La ricorsione in profondità arbitraria, necessaria per liste arbitrariamente annidate, non funziona bene con la massima profondità di ricorsione conservativa di Python. Il ragionamento per la rimozione del compilatore è in gran parte dovuto al fatto che è un pasticcio . Il compilatore è stato trasformato in ast , ma il flatten è rimasto indietro.

La profondità arbitraria può essere raggiunta con gli array di numpy e con quella appiattita della libreria.

    
risposta data 24.08.2014 - 07:38
fonte
-2

... forse perché non è difficile scriverne uno da solo

def flatten(l): return flatten(l[0]) + (flatten(l[1:]) if len(l) > 1 else []) if type(l) is list else [l]

... e poi appiattisci tutto ciò che vuoi:)

>>> flatten([1,[2,3],4])
[1, 2, 3, 4]
>>> flatten([1, [2, 3], 4, [5, [6, {'name': 'some_name', 'age':30}, 7]], [8, 9, [10, [11, [12, [13, {'some', 'set'}, 14, [15, 'some_string'], 16], 17, 18], 19], 20], 21, 22, [23, 24], 25], 26, 27, 28, 29, 30])
[1, 2, 3, 4, 5, 6, {'age': 30, 'name': 'some_name'}, 7, 8, 9, 10, 11, 12, 13, set(['set', 'some']), 14, 15, 'some_string', 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
>>> 
    
risposta data 08.04.2016 - 15:16
fonte

Leggi altre domande sui tag