12 ottobre, 2019

Normalizzare (flatten) liste annidate


Una procedura che mi mancava, in Python, adesso c'è. La funzione flatten opera esattamente come quella predefinita in Racket (e altri linguaggi, Ruby p.es.).

Se ne trovano tante nel Web; tutte riconducibili a poche progenitrici, tutti copiano tutti (evidentemente). E ho copiato anch'io, poi l'ho personalizzata, lambdizzata.

In StackExchange c'è Why doesn't Python have a “flatten” function for lists? che era la stessa domanda mia. La risposta --si trova sulla stessa pagina-- è che è una cosa troppo semplice per fornire una funzione di sistema; ma allora funzioni (in realtà metodi) come upper perché? In ogni caso eccola:

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

Quando una funzione è composta da una sola istruzione io preferisco definirla usando lambda, forse solo questione di gusti:

flatten = lambda l : flatten(l[0]) + (flatten(l[1:]) \
            if len(l) > 1 else []) if type(l) is list \
            or type(l) is tuple else [l]


Nota: andato a capo solo per il blog, la riga sarebbe troppo lunga.

Non resta che provarla, con liste o tuple o combinazioni delle due:

>>> flatten = lambda l : flatten(l[0]) + (flatten(l[1:]) \
...             if len(l) > 1 else []) if type(l) is list \
...             or type(l) is tuple else [l]
>>> lst = [1, [2, 3], [4, [5, 6]]]
>>> flatten(lst)
[1, 2, 3, 4, 5, 6]
>>> flatten([1])
[1]
>>> flatten([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
IndexError: list index out of range
>>> flatten(1)
[1]
>>> tpl = (1, (2, 3), (4, (5, 6)))
>>> flatten(tpl)
[1, 2, 3, 4, 5, 6]
>>> from copy import deepcopy
>>> mlt = deepcopy(lst)
>>> mlt.append(tpl)
>>> mlt
[1, [2, 3], [4, [5, 6]], (1, (2, 3), (4, (5, 6)))]
>>> flatten(mlt)
[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
>>>


OK, funziona tranne che con la lista (o tupla) vuota; si potrebbe (non nella versione lambda) testare se ritornare [] per [] o () ma non so se è il caso.
🔴

Nessun commento:

Posta un commento