Entrelacement de plusieurs listes en Python
7 réponses
Après avoir posté la question, j'ai réalisé que je peux simplement faire ce qui suit:
[val for pair in zip(l1, l2) for val in pair]
Où l1
et l2
sont les deux listes.
S'il y a N listes à entrelacer, alors
lists = [l1, l2, ...]
[val for tup in zip(*lists) for val in tup]
Pour plus de recettes, suivez La meilleure façon d'entrelacer une liste avec ses valeurs de suffixe . Certaines des méthodes démontrées peuvent être généralisées à deux ou plusieurs listes de longueur égale.
Pour python> = 2.3, il y a syntaxe de tranche étendue :
>>> a = [0, 2, 4, 6, 8]
>>> b = [1, 3, 5, 7, 9]
>>> c = a + b
>>> c[::2] = a
>>> c[1::2] = b
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
La ligne c = a + b
est utilisée comme un moyen simple de créer une nouvelle liste de la longueur exacte (à ce stade, son contenu n'est pas important). Les deux lignes suivantes font le travail réel d'entrelacement a
et b
: la première assigne les éléments de a
à tous les index pairs de c
; la seconde assigne les éléments de b
à tous les index impairs de c
.
Compte tenu de
a = [1, 2, 3]
b = [10, 20, 30]
c = [10, 20, 30, 99]
Code
En supposant des listes de longueur égale, vous pouvez obtenir une liste entrelacée avec itertools.chain
et zip
:
import itertools
list(itertools.chain(*zip(a, b)))
# [1, 10, 2, 20, 3, 30]
Solutions de rechange
Plus généralement avec des listes inégales, utilisez zip_longest
(recommandé):
[x for x in itertools.chain(*itertools.zip_longest(a, c)) if x is not None]
# [1, 100, 2, 200, 3, 300, 999]
De nombreuses listes peuvent être entrelacées en toute sécurité:
[x for x in itertools.chain(*itertools.zip_longest(a, b, c)) if x is not None]
# [1, 10, 100, 2, 20, 200, 3, 30, 300, 999]
Une bibliothèque qui est livrée avec le roundrobin
itertools recette, interleave
et interleave_longest
.
import more_itertools
list(more_itertools.roundrobin(a, b))
# [1, 10, 2, 20, 3, 30]
list(more_itertools.interleave(a, b))
# [1, 10, 2, 20, 3, 30]
list(more_itertools.interleave_longest(a, c))
# [1, 100, 2, 200, 3, 300, 999]
yield from
Enfin, pour quelque chose d'intéressant en Python 3 (bien que non recommandé):
list(filter(None, ((yield from x) for x in zip(a, b))))
# [1, 10, 2, 20, 3, 30]
list([(yield from x) for x in zip(a, b)])
# [1, 10, 2, 20, 3, 30]
+Installer via > pip install more_itertools
Alternative:
>>> l1=[1,2,3]
>>> l2=[10,20,30]
>>> [y for x in map(None,l1,l2) for y in x if y is not None]
[1, 10, 2, 20, 3, 30]
Cela fonctionne parce que map fonctionne sur les listes en parallèle. Il fonctionne de la même manière sous 2.2. En soi, avec None
comme fonctions appelées, map
produit une liste de tuples:
>>> map(None,l1,l2,'abcd')
[(1, 10, 'a'), (2, 20, 'b'), (3, 30, 'c'), (None, None, 'd')]
Ensuite, il suffit d'aplatir la liste des tuples.
L'avantage, bien sûr, est que {[4] } fonctionnera pour n'importe quel nombre de listes et fonctionnera même si elles sont de longueurs différentes:
>>> l1=[1,2,3]
>>> l2=[10,20,30]
>>> l3=[101,102,103,104]
>>> [y for x in map(None,l1,l2,l3) for y in x if y in not None]
[1, 10, 101, 2, 20, 102, 3, 30, 103, 104]
J'avais besoin d'un moyen de le faire avec des listes de tailles différentes que la réponse acceptée n'aborde pas.
Ma solution utilise un générateur et son utilisation semble un peu plus agréable à cause de cela:
def interleave(l1, l2):
iter1 = iter(l1)
iter2 = iter(l2)
while True:
try:
if iter1 != None:
yield next(iter1)
except StopIteration:
iter1 = None
try:
if iter2 != None:
yield next(iter2)
except StopIteration:
iter2 = None
if iter1 == None and iter2 == None:
raise StopIteration()
Et son utilisation:
>>> a = [1, 2, 3, 4, 5]
>>> b = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> list(interleave(a, b))
[1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 'e', 'f', 'g']
>>> list(interleave(b, a))
['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f', 'g']
J'aime mieux la solution d'aix. voici une autre façon que je pense devrait fonctionner en 2.2:
>>> x=range(3)
>>> x
[0, 1, 2]
>>> y=range(7,10)
>>> y
[7, 8, 9]
>>> sum(zip(x,y),[])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "tuple") to list
>>> sum(map(list,zip(x,y)),[])
[0, 7, 1, 8, 2, 9]
Et une autre façon:
>>> a=[x,y]
>>> [a[i][j] for j in range(3) for i in (0,1)]
[0, 7, 1, 8, 2, 9]
Et:
>>> sum((list(i) for i in zip(x,y)),[])
[0, 7, 1, 8, 2, 9]
[el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None]
Tant Que vous n'avez pas None
que vous voulez garder