Come posso convertire una tupla di tuple in un elenco unidimensionale utilizzando la comprensione delle liste?[duplicare]

StackOverflow https://stackoverflow.com/questions/3204245

Domanda

Ho una tupla di tuple, ad esempio:

tupleOfTuples = ((1, 2), (3, 4), (5,))

Voglio convertirlo in un elenco piatto e unidimensionale di tutti gli elementi in ordine:

[1, 2, 3, 4, 5]

Ho cercato di ottenere questo risultato con la comprensione delle liste.Ma non riesco a capirlo.Sono stato in grado di realizzarlo con un ciclo for-each:

myList = []
for tuple in tupleOfTuples:
   myList = myList + list(tuple)

Ma sento che ci deve essere un modo per farlo con una comprensione dell'elenco.

Un semplice [list(tuple) for tuple in tupleOfTuples] ti dà semplicemente un elenco di elenchi, invece di singoli elementi.Ho pensato che forse avrei potuto basarmi su questo utilizzando l'operatore unpacking per poi decomprimere l'elenco, in questo modo:

[*list(tuple) for tuple in tupleOfTuples]

O

[*(list(tuple)) for tuple in tupleOfTuples]

...ma non ha funzionato.Qualche idea?O dovrei semplicemente attenermi al loop?

È stato utile?

Soluzione

è tipicamente indicato come appiattimento di una struttura annidata.

>>> tupleOfTuples = ((1, 2), (3, 4), (5,))
>>> [element for tupl in tupleOfTuples for element in tupl]
[1, 2, 3, 4, 5]
.

Solo per dimostrare l'efficienza:

>>> import timeit
>>> it = lambda: list(chain(*tupleOfTuples))
>>> timeit.timeit(it)
2.1475738355700913
>>> lc = lambda: [element for tupl in tupleOfTuples for element in tupl]
>>> timeit.timeit(lc)
1.5745135182887857
.

ETA : Si prega di non utilizzare tuple come nome di variabile, ombre IT Built-In.

Altri suggerimenti

Basta usare sum se non hai molte tuple.

>>> tupleOfTuples = ((1, 2), (3, 4), (5,))
>>> sum(tupleOfTuples, ())
(1, 2, 3, 4, 5)
>>> list(sum(tupleOfTuples, ())) # if you really need a list
[1, 2, 3, 4, 5]

Se hai molte tuple, usa comprensione delle liste O chain.from_iterable per impedire il comportamento quadratico di sum.


Micro-benchmark:

  • Pitone 2.6

    • Tupla lunga di tuple corte

      $ python2.6 -m timeit -s 'tot = ((1, 2), )*500' '[element for tupl in tot for element in tupl]'
      10000 loops, best of 3: 134 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, 2), )*500' 'list(sum(tot, ()))'
      1000 loops, best of 3: 1.1 msec per loop
      $ python2.6 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
      10000 loops, best of 3: 60.1 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain' 'list(chain(*tot))'
      10000 loops, best of 3: 64.8 usec per loop
      
    • Tupla corta di tuple lunghe

      $ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500)' '[element for tupl in tot for element in tupl]'
      10000 loops, best of 3: 65.6 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500)' 'list(sum(tot, ()))'
      100000 loops, best of 3: 16.9 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
      10000 loops, best of 3: 25.8 usec per loop
      $ python2.6 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain' 'list(chain(*tot))'
      10000 loops, best of 3: 26.5 usec per loop
      
  • Pitone 3.1

    • Tupla lunga di tuple corte

      $ python3.1 -m timeit -s 'tot = ((1, 2), )*500' '[element for tupl in tot for element in tupl]'
      10000 loops, best of 3: 121 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, 2), )*500' 'list(sum(tot, ()))'
      1000 loops, best of 3: 1.09 msec per loop
      $ python3.1 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
      10000 loops, best of 3: 59.5 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, 2), )*500; from itertools import chain' 'list(chain(*tot))'
      10000 loops, best of 3: 63.2 usec per loop
      
    • Tupla corta di tuple lunghe

      $ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500)' '[element for tupl in tot for element in tupl]'
      10000 loops, best of 3: 66.1 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500)' 'list(sum(tot, ()))'
      100000 loops, best of 3: 16.3 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain; ci = chain.from_iterable' 'list(ci(tot))'
      10000 loops, best of 3: 25.4 usec per loop
      $ python3.1 -m timeit -s 'tot = ((1, )*500, (2, )*500); from itertools import chain' 'list(chain(*tot))'
      10000 loops, best of 3: 25.6 usec per loop
      

Osservazione:

  • sum è più veloce se la tupla esterna è corta.
  • list(chain.from_iterable(x)) è più veloce se la tupla esterna è lunga.

Stai concatenando insieme le tuple:

from itertools import chain
print list(chain(*listOfTuples))
.

dovrebbe essere piuttosto leggibile se hai familiarità con itertools e senza il generatore di generazione esplicito hai persino il risultato del modulo generatore.

Mi piace usare 'Riduci' in questa situazione (questo è ciò che si riduce per!)

lot = ((1, 2), (3, 4), (5,))
print list(reduce(lambda t1, t2: t1 + t2, lot))

 > [1,2,3,4,5]
.

La maggior parte di queste risposte funzionerà solo per un unico livello di appiattimento.Per una soluzione più completa, prova questo (da http:// rexfootin.blogspot.com / 2006/09 / 09 / more-on-python-flatten.html ):

def flatten(l, ltypes=(list, tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        i += 1
    return ltype(l)
.

Per il codice multilivello e il codice leggibile:

def flatten(bla):
    output = []
    for item in bla:
        output += flatten(item) if hasattr (item, "__iter__") or hasattr (item, "__len__") else [item]
    return output
.

Non ho potuto ottenere questo per adattarsi in una riga (e rimanere leggibile, anche di gran lunga)

Un'altra soluzione utilizzando itertools.chain

>>> tupleOfTuples = ((1, 2), (3, 4), (5,))
>>> from itertools import chain
>>> [x for x in chain.from_iterable(tupleOfTuples)]
[1, 2, 3, 4, 5]
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top