Interleave multiple lists of the same length in Python

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.


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


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

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]

Tags:

Python

List