web-dev-qa-db-fra.com

Concaténation de nombreuses listes en Python

Supposons que j'ai une fonction comme celle-ci:

def getNeighbors(vertex)

qui retourne une liste de sommets voisins du sommet donné. Maintenant, je veux créer une liste avec tous les voisins des voisins. Je fais ça comme ça:

listOfNeighborsNeighbors = []
for neighborVertex in getNeighbors(vertex):
    listOfNeighborsNeighbors.append(getNeighbors(neighborsVertex))

Y a-t-il une façon plus Pythonique de le faire?

36
Björn Pollex
[x for n in getNeighbors(vertex) for x in getNeighbors(n)]

ou

sum(getNeighbors(n) for n in getNeighbors(vertex), [])
37

Comme d'habitude, le module itertools contient une solution:

>>> l1=[1, 2, 3]

>>> l2=[4, 5, 6]

>>> l3=[7, 8, 9]

>>> import itertools

>>> list(itertools.chain(l1, l2, l3))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
57
Jochen

L'ajout de listes peut se faire avec + et sum ():

>>> c = [[1, 2], [3, 4]]
>>> sum(c, [])
[1, 2, 3, 4]
36
Sjoerd

Si la vitesse est importante, il peut être préférable d'utiliser ceci:

from operator import iadd
reduce(iadd, (getNeighbors(n) for n in getNeighbors(vertex)))

Le but de ce code est de concaténer des listes entières par list.extend Où la compréhension de liste ajouterait un élément par un, comme si on appelait list.append. Cela économise un peu de frais généraux, ce qui rend le premier (selon mes mesures) environ trois fois plus rapide. (L'opérateur iadd est normalement écrit comme += Et fait la même chose que list.extend.)

Utiliser des compréhensions de liste (la première solution d'Ignacio) est toujours la bonne façon, elle est plus facile à lire.

Mais évitez certainement d'utiliser sum(..., []), car il s'exécute en temps quadratique. C'est très impraticable pour beaucoup listes (plus d'une centaine).

13
emu

Tri par vitesse:

list_of_lists = [[x,1] for x in xrange(1000)]

%timeit list(itertools.chain(*list_of_lists))
100000 loops, best of 3: 14.6 µs per loop

%timeit list(itertools.chain.from_iterable(list_of_lists))
10000 loops, best of 3: 60.2 µs per loop

min(timeit.repeat("ll=[];\nfor l in list_of_lists:\n ll.extend(l)", "list_of_lists=[[x,1] for x in xrange(1000)]",repeat=3, number=100))/100.0
9.620904922485351e-05

%timeit [y for z in list_of_lists for y in z]
10000 loops, best of 3: 108 µs per loop

%timeit sum(list_of_lists, [])
100 loops, best of 3: 3.7 ms per loop
11
Yariv

J'aime l'approche itertools.chain Car elle s'exécute en temps linéaire (la somme (...) s'exécute en temps qudratique) mais @Jochen n'a pas montré comment gérer les listes de longueur dynamique. Voici la solution à la question d'OP.

import itertools
list(itertools.chain(*[getNeighbors(n) for n in getNeighbors(vertex)]))

Vous pouvez vous débarrasser de l'appel de list(...) si l'itérable vous suffit.

2
renadeen

L'utilisation de . Extend () (mise à jour sur place) combinée à réduire au lieu de sum () (nouvel objet à chaque fois) devrait être plus efficace mais je suis trop paresseux pour tester cette :)

mylist = [[1,2], [3,4], [5,6]] 
reduce(lambda acc_l, sl: acc_l.extend(sl) or acc_l, mylist)
0
realmaniek