# New list from the elements of two lists popping sequentially

Can this be shortened, optimised or made more pythonic ?

a = [1,9,'foo',5,7]
b = ['bar',4,8,6]
c = []

min_len = min(len(a),len(b))

for i in range(min_len):
c.extend([a.pop(0), b.pop(0)])

c.extend(a)
c.extend(b)

print c


output: [1, 'bar', 9, 4, 'foo', 8, 5, 6, 7]

If the lists cannot contain None as a valid item that you want copied to c, you can use this:

from itertools import izip_longest

c = [item for items in izip_longest(a, b) for item in items if item is not None]


It is shorter/concise*, doesn't modify the original lists and probably performs a bit better.

*Yet it doesn't look so elegant, but it's a common pattern in Python, which is most important.

As a bonus, it scales to more lists easily.

There are a few possibilities...

from itertools import chain, izip_longest
def alternate(a, b):
for i in range(max(len(a), len(b))):
if i < len(a):
yield a[i]
if i < len(b):
yield b[i]

def alternate2(list_a, list_b):
unfound = {}
for a, b in izip_longest(list_a, list_b, fill=unfound):
if a is not unfound:
yield a
if b is not unfound:
yield b

a = [1,9,'foo',5,7]
b = ['bar',4,8,6]
print list(alternate(a, b))
print list(alternate2(a, b))
print list(chain.from_iterable(zip(a, b))) + a[len(b):] + b[len(a):]

• not sure about those A/B for local variables. – tokland Aug 6 '13 at 9:32

I would avoid doing x.pop(0) because it is slow (unlike x.pop(), by the way). Instead, I would write (in Python 2):

import itertools

def alternate(a, b):
"""Yield alternatingly from two lists, then yield the remainder of the longer list."""
for A, B in itertools.izip(a, b):
yield A
yield B
for X in a[len(b):] or b[len(a):]:
yield X

print list(alternate([1, 2, 3, 4, 5], ["a", "b", "c"]))


In Python 3, itertools.izip becomes zip and, as tokland has noted, we can use yield from in Python 3.3:

def alternate(a, b):
"""Yield alternatingly from two lists, then yield the remainder of the longer list."""
for A, B in zip(a, b):
yield A
yield B
yield from a[len(b):] or b[len(a):]

print(list(alternate([1, 2, 3, 4, 5], ["a", "b", "c"])))


The following will work with any kind of iterables:

def alternate(a, b):
"""Yield alternatingly from two iterables, then yield the remainder of the longer one."""
x, y = iter(a), iter(b)
while True:
try:
yield next(x)
except StopIteration:
yield from y
return
x, y = y, x


I'd write:

import itertools

def alternate(xs, ys):

print(list(alternate([1, 2, 3, 4, 5], ["a", "b", "c"])))
# [1, 'a', 2, 'b', 3, 'c', 4, 5]


Another solution without itertools and using the (long-awaited) yield from construction added in Python 3.3:

def alternate(xs, ys):
yield from (z for zs in zip(xs, ys) for z in zs)
yield from (xs[len(ys):] if len(xs) > len(ys) else ys[len(xs):])


Without pop, yield or itertools

c = []
for i,x in enumerate(zip(a,b)):
c.extend(x)
i += 1
c.extend(a[i:])
c.extend(b[i:])


In older versions the loop could be written as a comprehension, but in newer ones i is not accessible outside the loop. But:

c = [y for x in zip(a,b) for y in x]
i = len(c)//2  # or i = min(len(a),len(b))
c.extend(a[i:])
c.extend(b[i:])


At its core, this is a question of how to flatten zip(a,b). https://stackoverflow.com/questions/406121/flattening-a-shallow-list-in-python makes the case that itertools.chain is somewhat faster than the comprehension, though not drastically so.

c = chain.from_iterable(zip(a,b)) # or
c = chain(*zip(a,b))

• Why would one avoid yield (a language construct) or itertools (batteries included, what Python is famous for)? – Thijs van Dien Aug 7 '13 at 16:54