110 votes

Entrelacer plusieurs listes de même longueur en Python

En Python, existe-t-il un bon moyen d'entrelacer deux listes de même longueur ?

Dites que je suis donné [1,2,3] et [10,20,30] . J'aimerais les transformer en [1,10,2,20,3,30] .

0 votes

Non recommandé, mais essayez ceci : it = iter(l1); list((yield next(it)) or i for i in l2)

0 votes

146voto

NPE Points 169956

Après avoir posé la question, je me suis rendu compte que je peux simplement faire ce qui suit :

[val for pair in zip(l1, l2) for val in pair]

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]

6 votes

Ne fonctionne que si l1 et l2 ont le même nombre d'éléments

27 votes

@Emmanuel : La question est la suivante : "En Python, existe-t-il un bon moyen d'entrelacer deux listes ? de la même longueur ?"

3 votes

Si vous souhaitez ajouter un pad à la liste la plus longue, utilisez izip_longest pour python2 et zip_longest pour python3 ` [val for pair in itertools.zip_longest(l1, l2) for val in pair] les résultats avec ['a', 'b', 'a', 'b', 'a', 'b', None, 'b', None, 'b', None, 'b']

82voto

ekhumoro Points 23190

Pour Python>=2.3, il y a syntaxe étendue de la tranche :

>>> 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é comme un moyen simple de créer une nouvelle liste ayant exactement la bonne longueur (à ce stade, son contenu n'est pas important). Les deux lignes suivantes effectuent le travail d'entrelacement proprement dit a et b le premier attribue 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 .

39voto

pylang Points 12013

Étant donné que

a = [1, 2, 3]
b = [10, 20, 30]
c = [100, 200, 300, 999]

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]

Alternatives

_itertools.zip_longest_

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 imbriqué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]

_more_itertools_ +

Une bibliothèque qui est livrée avec le roundrobin recette itertools, 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]

<sup>+ </sup>Installer en utilisant <code>pip install more_itertools</code>

9voto

Sandy Chapman Points 831

J'avais besoin d'un moyen de faire cela avec des listes de tailles différentes, ce que la réponse acceptée ne permet pas de faire.

Ma solution utilise un générateur et son utilisation est un peu plus agréable grâce à lui :

def interleave(l1, l2):
    iter1 = iter(l1)
    iter2 = iter(l2)
    while True:
        try:
            if iter1 is not None:
                yield next(iter1)
        except StopIteration:
            iter1 = None
        try:
            if iter2 is not None:
                yield next(iter2)
        except StopIteration:
            iter2 = None
        if iter1 is None and iter2 is 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']

1 votes

Le site roundrobin recette du itertools module est une extension plus générale de ce principe.

7voto

the wolf Points 10164

Alternatif :

>>> 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 carte travaille sur des 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 map 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]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X