Interleave multiple lists of the same length in Python

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

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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]

Method 2

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.

Method 3

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

Method 4

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

Method 5

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]

Method 6

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]

Method 7

A funny approach is to use heapq.merge with the position in the final list as key:

from heapq import merge
from itertools import count

a = [1,2,3]
b = [10,20,30]

counter = count()
res = list(merge(a, b, key=lambda x: next(counter)))
print(res)

Output

[1, 10, 2, 20, 3, 30]

For multiple list, you can just unpack them:

from heapq import merge
from itertools import count

a = [1, 2, 3]
b = [10, 20, 30]
c = [11, 21, 31]

counter = count()
res = list(merge(*[a, b, c], key=lambda x: next(counter)))
print(res)

Output

[1, 10, 11, 2, 20, 21, 3, 30, 31]

Method 8

This is also a way to do it:

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

list(sum(zip(list1, list2), ()))

The idea is similar.

  1. zip the lists together. (using zip)
  2. flatten to a tuple (using sum(…, ())
  3. convert to a list

Method 9

[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

Method 10

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]

Method 11

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]


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x