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?
[x for n in getNeighbors(vertex) for x in getNeighbors(n)]
ou
sum(getNeighbors(n) for n in getNeighbors(vertex), [])
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]
L'ajout de listes peut se faire avec + et sum ():
>>> c = [[1, 2], [3, 4]]
>>> sum(c, [])
[1, 2, 3, 4]
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).
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
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.
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)