Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interleave two lists of different length in python v. 2?

I am trying to write a Python function that takes two lists as arguments and interleaves them. The order of the component lists should be preserved. If the lists do not have the same length, the elements of the longer list should end up at the end of the resulting list. For example, I'd like to put this in Shell:

interleave(["a", "b"], [1, 2, 3, 4])

And get this back:

["a", 1, "b", 2, 3, 4]

If you can help me I'd appreciate it.

like image 383
Rebecca Avatar asked Nov 03 '22 12:11

Rebecca


2 Answers

Here's how I'd do it, using various bits of the itertools module. It works for any number of iterables, not just two:

from itertools import chain, izip_longest # or zip_longest in Python 3
def interleave(*iterables):

    sentinel = object()
    z = izip_longest(*iterables, fillvalue = sentinel)
    c = chain.from_iterable(z)
    f = filter(lambda x: x is not sentinel, c)

    return list(f)
like image 197
Blckknght Avatar answered Nov 14 '22 21:11

Blckknght


You could try this:

In [30]: from itertools import izip_longest

In [31]: l = ['a', 'b']

In [32]: l2 = [1, 2, 3, 4]

In [33]: [item for slist in izip_longest(l, l2) for item in slist if item is not None]
Out[33]: ['a', 1, 'b', 2, 3, 4]

izip_longest 'zips' the two lists together, but instead of stopping at the length of the shortest list, it continues until the longest one is exhausted:

In [36]: list(izip_longest(l, l2))
Out[36]: [('a', 1), ('b', 2), (None, 3), (None, 4)]

You then add items by iterating through each item in each pair in the zipped list, omitting those that have a value of None. As pointed out by @Blckknight, this will not function properly if your original lists have None values already. If that is possible in your situation, you can use the fillvalue property of izip_longest to fill with something other than None (as @Blckknight does in his answer).

Here is the above example as a function:

In [37]: def interleave(*iterables):
   ....:     return [item for slist in izip_longest(*iterables) for item in slist if item is not None]
   ....:

In [38]: interleave(l, l2)
Out[38]: ['a', 1, 'b', 2, 3, 4]

In [39]: interleave(l, l2, [44, 56, 77])
Out[39]: ['a', 1, 44, 'b', 2, 56, 3, 77, 4]
like image 45
RocketDonkey Avatar answered Nov 14 '22 21:11

RocketDonkey