Je me demande s'il existe un raccourci pour créer une liste simple à partir d'une liste de listes en Python.
Je peux le faire dans une boucle for
, mais peut-être qu'il y a quelque chose de cool à faire en une seule fois ? J'ai essayé avec reduce()
, mais j'obtiens une erreur.
Code
l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]
reduce(lambda x, y: x.extend(y), l)
Message d'erreur
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: 'NoneType' object has no attribute 'extend'
Étant donné une liste de listes l
,
`flat_list = [item for sublist in l for item in sublist]``
ce qui signifie :
flat_list = []
for sublist in l:
for item in sublist:
flat_list.append(item)
est plus rapide que les raccourcis postés jusqu'à présent. (l
est la liste à aplatir).
Voici la fonction correspondante :
flatten = lambda l: [item for sublist in l for item in sublist]
Comme preuve, vous pouvez utiliser le module timeit
de la bibliothèque standard :
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 1.1 msec per loop
Explication : les raccourcis basés sur +
(y compris l'utilisation implicite dans sum
) sont, par nécessité, O(L**2)
quand il y a L sous-listes -- comme la liste de résultats intermédiaires continue à s'allonger, à chaque étape un nouvel objet de liste de résultats intermédiaires est alloué, et tous les éléments du résultat intermédiaire précédent doivent être copiés (ainsi que quelques nouveaux éléments ajoutés à la fin). Ainsi, pour simplifier et sans perte réelle de généralité, disons que vous avez L sous-listes de I éléments chacune : les I premiers éléments sont copiés dans les deux sens L-1 fois, les I seconds L-2 fois, et ainsi de suite ; le nombre total de copies est I fois la somme de x pour x de 1 à L exclus, c'est-à-dire I * (L**2)/2
.
La compréhension de liste ne génère qu'une seule liste, une seule fois, et copie chaque élément (de son emplacement d'origine à la liste de résultat) également exactement une fois.
Note de l'auteur : C'est inefficace. Mais amusant, parce que les monoïdes sont géniaux. Ce n'est pas approprié pour le code Python de production.
>>> sum(l, [])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Ceci additionne juste les éléments de l'itérable passés dans le premier argument, en traitant le second argument comme la valeur initiale de la somme (s'il n'est pas donné, 0
est utilisé à la place et ce cas vous donnera une erreur).
Comme vous additionnez des listes imbriquées, vous obtenez en fait [1,3]+[2,4]
comme résultat de sum([[1,3],[2,4]],[])
, qui est égal à [1,3,2,4]
.
Notez que cela ne fonctionne que pour les listes de listes. Pour les listes de listes de listes, vous aurez besoin d'une autre solution.
from functools import reduce #python 3
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(lambda x,y: x+y,l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
La méthode extend()
de votre exemple modifie x
au lieu de retourner une valeur utile (ce que reduce()
attend).
Une façon plus rapide de faire la version reduce
serait la suivante
>>> import operator
>>> l = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, l)
[1, 2, 3, 4, 5, 6, 7, 8, 9]