95

In Python, is there a good way to interleave two lists of the same length?

Say I'm given [1,2,3] and [10,20,30]. I'd like to transform those into [1,10,2,20,3,30].

Georgy
  • 6,348
  • 7
  • 46
  • 58
NPE
  • 438,426
  • 93
  • 887
  • 970
  • Not recommended, but try this: `it = iter(l1); list((yield next(it)) or i for i in l2)` – Chris_Rands Jul 12 '17 at 11:48
  • Does this answer your question? [Pythonic way to combine two lists in an alternating fashion?](https://stackoverflow.com/questions/3678869/pythonic-way-to-combine-two-lists-in-an-alternating-fashion) – Vaidøtas I. Jan 04 '21 at 20:18

9 Answers9

126

Having posted the question, I've realised that I can simply do the following:

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

where l1 and l2 are the two lists.


If there are N lists to interleave, then

lists = [l1, l2, ...]
[val for tup in zip(*lists) for val in tup]
Georgy
  • 6,348
  • 7
  • 46
  • 58
NPE
  • 438,426
  • 93
  • 887
  • 970
  • 5
    works only if l1 and l2 have the same number of elements – Emmanuel Oct 07 '16 at 13:58
  • 16
    @Emmanuel: The question reads "In Python, is there a good way to interleave two lists **of the same length**?" – NPE Oct 08 '16 at 11:21
  • 1
    If you'd like to pad to longest list, use `izip_longest` for python2 and `zip_longest` for python3 ` `[val for pair in itertools.zip_longest(l1, l2) for val in pair]` results with `['a', 'b', 'a', 'b', 'a', 'b', None, 'b', None, 'b', None, 'b']` – Sergey Zakharov Nov 16 '17 at 18:22
78

For Python>=2.3, there's extended slice syntax:

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

The line c = a + b is used as a simple way to create a new list of exactly the right length (at this stage, its contents are not important). The next two lines do the actual work of interleaving a and b: the first one assigns the elements of a to all the even-numbered indexes of c; the second one assigns the elements of b to all the odd-numbered indexes of c.

ekhumoro
  • 98,079
  • 17
  • 183
  • 279
30

Given

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

Code

Assuming lists of equal length, you can get an interleaved list with itertools.chain and zip:

import itertools


list(itertools.chain(*zip(a, b)))
# [1, 10, 2, 20, 3, 30]

Alternatives

itertools.zip_longest

More generally with unequal lists, use zip_longest (recommended):

[x for x in itertools.chain(*itertools.zip_longest(a, c)) if x is not None]
# [1, 100, 2, 200, 3, 300, 999]

Many lists can safely be interleaved:

[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+

A library that ships with the roundrobin itertools recipe, interleave and 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

Finally, for something interesting in Python 3 (though not recommended):

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]

+Install using pip install more_itertools

pylang
  • 28,402
  • 9
  • 97
  • 94
8

I needed a way to do this with lists of different sizes which the accepted answer doesn't address.

My solution uses a generator and its usage looks a bit nicer because of it:

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()

And its usage:

>>> 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']
ShadowRanger
  • 108,619
  • 9
  • 124
  • 184
Sandy Chapman
  • 10,385
  • 3
  • 55
  • 63
  • [The `roundrobin` recipe from the `itertools` module](https://docs.python.org/3/library/itertools.html#itertools-recipes) is a more general extension of this. – ShadowRanger Oct 15 '20 at 23:14
7

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]

This works because map works on lists in parallel. It works the same under 2.2. By itself, with None as the called functions, map produces a list of tuples:

>>> map(None,l1,l2,'abcd')
[(1, 10, 'a'), (2, 20, 'b'), (3, 30, 'c'), (None, None, 'd')]

Then just flatten the list of tuples.

The advantage, of course, is map will work for any number of lists and will work even if they are different lengths:

>>> 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]
the wolf
  • 29,808
  • 12
  • 50
  • 71
3

I like aix's solution best. here is another way I think should work in 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]

and one more way:

>>> a=[x,y]
>>> [a[i][j] for j in range(3) for i in (0,1)]
[0, 7, 1, 8, 2, 9]

and:

>>> sum((list(i) for i in zip(x,y)),[])
[0, 7, 1, 8, 2, 9]
robert king
  • 14,265
  • 8
  • 84
  • 107
0
[el for el in itertools.chain(*itertools.izip_longest([1,2,3], [4,5])) if el is not None]

As long as you don't have None that you want to keep

jon_darkstar
  • 15,278
  • 6
  • 24
  • 34
0

To answer the question's title of "Interleave multiple lists of the same length in Python", we can generalize the 2-list answer of @ekhumoro. This explicitly requires that the lists are the same length, unlike the (elegant) solution by @NPE

import itertools

def interleave(lists):
    """Interleave a list of lists.

    :param lists: List of lists; each inner length must be the same length.
    :returns: interleaved single list
    :rtype: list

    """
    if len(set(len(_) for _ in lists)) > 1:
        raise ValueError("Lists are not all the same length!")
    joint = list(itertools.chain(*lists))
    for l_idx, li in enumerate(lists):
        joint[l_idx::len(lists)] = li
    return joint

Examples:

>>> interleave([[0,2,4], [1, 3, 5]])
[0, 1, 2, 3, 4, 5]
>>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12]])
[0, 1, 10, 2, 3, 11, 4, 5, 12]
>>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14, 15]])
[0, 1, 10, 13, 2, 3, 11, 14, 4, 5, 12, 15]
>>> interleave([[0,2,4], [1, 3, 5], [10, 11, 12], [13, 14]])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 10, in interleave
ValueError: Lists are not all the same length!
>>> interleave([[0,2,4]])
[0, 2, 4]
eqzx
  • 4,167
  • 3
  • 30
  • 48
0

Too late to the party, and there is plenty of good answers but I would also like to provide a simple solution using extend() method:

list1 = [1, 2, 3]
list2 = [10, 20, 30]

new_list = []
for i in range(len(list1)):
    new_list.extend([list1[i], list2[i]])
print(new_list)

Output:

[1, 10, 2, 20, 3, 30]
Amit Yadav
  • 2,613
  • 3
  • 15
  • 50