Comment convertir un tuple de tuples en liste unidimensionnelle en utilisant la compréhension de liste? [dupliquer]

cette question a déjà une réponse ici:

j'ai un tuple de tuples-par exemple:

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

je veux transformer ceci en une liste plate, unidimensionnelle de tous les les éléments dans l'ordre:

[1, 2, 3, 4, 5]

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

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 liste.

simple [list(tuple) for tuple in tupleOfTuples] vous donne une liste de listes, au lieu d'éléments individuels. J'ai pensé que je pourrais peut-être construire sur ce en utilisant le opérateur de déballage pour ensuite déballer la liste, comme ceci:

[*list(tuple) for tuple in tupleOfTuples]

ou

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

... mais cela ne fonctionne pas. Des idées? Ou devrais-je m'en tenir à la boucle?

26
demandé sur froadie 2010-07-08 17:53:14

7 réponses

on appelle ça aplatir une structure emboîté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 : S'il vous plaît n'utilisez pas tuple comme nom variable, il ombrage intégré.

54
répondu SilentGhost 2010-07-08 14:29:50

il suffit d'utiliser 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 liste de compréhension ou chain.from_iterable pour prévenir le comportement quadratique de sum .


Micro-benchmarks:

  • Python 2.6

    • Long tuple de court tuples

      $ 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
      
    • Court tuple de long tuples

      $ 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

    • Long n-uplet de court tuples

      $ 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
      
    • Court tuple de long tuples

      $ 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 extérieur est court.
  • list(chain.from_iterable(x)) est plus rapide si le tuple extérieur est long.
33
répondu kennytm 2017-05-23 12:25:58

Vous êtes le chaînage de l'ensemble des n-uplets:

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

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

8
répondu Jochen Ritzel 2010-07-08 14:07:16

la plupart de ces réponses ne fonctionneront que pour un seul niveau d'aplatissement. Pour une solution plus complète, essayez ceci (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)
7
répondu Craig Trader 2010-07-08 14:15:17

j'aime "réduire" dans cette situation (c'est ce que réduire la!)

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

 > [1,2,3,4,5]
6
répondu Donald Miner 2010-07-08 13:58:38

pour le multilevel, et le code 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 obtenir ce pour tenir dans une seule ligne (et restent lisibles, même de loin)

4
répondu jsbueno 2010-07-08 15:52:27

une autre solution utilisant itértools.chaîne

>>> tupleOfTuples = ((1, 2), (3, 4), (5,))
>>> from itertools import chain
>>> [x for x in chain.from_iterable(tupleOfTuples)]
[1, 2, 3, 4, 5]
1
répondu Mad Scientist 2010-07-08 14:07:28