How to elegantly interleave two lists of uneven length in python?
Borrowing heavily from Jon Clements' solution, you could write a function that takes an arbitrary number of sequences and returns merged sequence of evenly-spaced items:
import itertools as IT
def evenly_spaced(*iterables):
"""
>>> evenly_spaced(range(10), list('abc'))
[0, 1, 'a', 2, 3, 4, 'b', 5, 6, 7, 'c', 8, 9]
"""
return [item[1] for item in
sorted(IT.chain.from_iterable(
zip(IT.count(start=1.0 / (len(seq) + 1),
step=1.0 / (len(seq) + 1)), seq)
for seq in iterables))]
iterables = [
['X']*2,
range(1, 11),
['a']*3
]
print(evenly_spaced(*iterables))
yields
[1, 2, 'a', 3, 'X', 4, 5, 'a', 6, 7, 'X', 8, 'a', 9, 10]
With the assumption that a
is the sequence to be inserted into:
from itertools import izip, count
from operator import itemgetter
import heapq
a = [1, 2, 3, 4]
b = ['a', 'b']
fst = enumerate(a)
snd = izip(count(0, len(a) // len(b)), b)
print map(itemgetter(1), heapq.merge(fst, snd))
# [1, 'a', 2, 3, 'b', 4]
if a
is the longer list and b
is the shorter
from itertools import groupby
len_ab = len(a) + len(b)
groups = groupby(((a[len(a)*i//len_ab], b[len(b)*i//len_ab]) for i in range(len_ab)),
key=lambda x:x[0])
[j[i] for k,g in groups for i,j in enumerate(g)]
eg
>>> a = range(8)
>>> b = list("abc")
>>> len_ab = len(a) + len(b)
>>> groups = groupby(((a[len(a)*i//len_ab], b[len(b)*i//len_ab]) for i in range(len_ab)), key=lambda x:x[0])
>>> [j[i] for k,g in groups for i,j in enumerate(g)]
[0, 'a', 1, 2, 'b', 3, 4, 5, 'c', 6, 7]
You can use this trick to make sure a
is longer than b
b, a = sorted((a, b), key=len)
This is basically the same as Bresenham's line algorithm. You can calculate "pixel" positions and use them as the indices into the lists.
Where your task differs is that you only want each element to show up once. You'd need to either modify the algorithm or post-process the indices, appending the elements from the lists only the first time they appear. There is a slight ambiguity, though: when both pixel/list indices change at the same time, you'll need to pick which one to include first. This corresponds to the two different options for interleaving the lists that are mentioned in the question and a comment.