web-dev-qa-db-fra.com

Comment convertir un Tuple de tuples en une liste unidimensionnelle en utilisant la compréhension de liste?

J'ai un tuple de tuples - par exemple:

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

Je veux convertir cela en une liste plate et unidimensionnelle de tous les éléments dans l'ordre:

[1, 2, 3, 4, 5]

J'ai essayé d'accomplir cela avec une compréhension de la liste. Mais je n'arrive pas à comprendre. J'ai pu l'accomplir avec une boucle pour chaque:

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

Mais je pense qu'il doit y avoir un moyen de le faire avec une compréhension de la liste.

Une simple [list(Tuple) for Tuple in tupleOfTuples] vous donne simplement une liste de listes, au lieu d'éléments individuels. J'ai pensé que je pourrais peut-être m'appuyer sur cela en utilisant l'opérateur de déballage pour ensuite décompresser la liste, comme ceci:

[*list(Tuple) for Tuple in tupleOfTuples]

ou

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

... mais cela n'a pas fonctionné. Des idées? Ou devrais-je simplement m'en tenir à la boucle?

30
froadie

il s'agit généralement d'aplatir une structure imbriquée.

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

Juste pour démontrer l'efficacité:

>>> 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 : Veuillez ne pas utiliser Tuple comme nom de variable, il crée des ombres intégrées.

61
SilentGhost

Utilisez simplement sum si vous n'avez pas beaucoup de tuples.

>>> 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]

Si vous avez beaucoup de tuples, utilisez compréhension de liste ou chain.from_iterable pour empêcher le comportement quadratique de sum.


Micro-repères:

  • Python 2.6

    • Tuple long de tuples courts

      $ 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
      
    • Tuple court de tuples longs

      $ 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
      
  • Python 3.1

    • Tuple long de tuples courts

      $ 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
      
    • Tuple court de tuples longs

      $ 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
      

Observation:

  • sum est plus rapide si le Tuple externe est court.
  • list(chain.from_iterable(x)) est plus rapide si le Tuple externe est long.
39
kennytm

Vous enchaînez les tuples ensemble:

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

Devrait être assez lisible si vous connaissez itertools, et sans le list explicite, vous avez même votre résultat sous forme de générateur.

10
Jochen Ritzel

La plupart de ces réponses ne fonctionneront que pour un seul niveau d'aplatissement. Pour une solution plus complète, essayez ceci (à partir de http://rightfootin.blogspot.com/2006/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)
9
Craig Trader

J'aime utiliser 'réduire' dans cette situation (c'est pour ça que réduire est fait!)

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

 > [1,2,3,4,5]
8
Donald Miner

Pour un code à plusieurs niveaux et lisible:

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

Je ne pouvais pas faire tenir cela sur une seule ligne (et rester lisible, même de loin)

4
jsbueno

Une autre solution utilisant 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]
1
Mad Scientist