5
\$\begingroup\$

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]

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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):]
\$\endgroup\$
  • \$\begingroup\$ not sure about those A/B for local variables. \$\endgroup\$ – tokland Aug 6 '13 at 9:32
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

I'd write:

import itertools

def alternate(xs, ys):
    head = itertools.chain.from_iterable(zip(xs, ys))
    return itertools.chain(head, xs[len(ys):], ys[len(xs):])

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):])
\$\endgroup\$
0
\$\begingroup\$

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))
\$\endgroup\$
  • \$\begingroup\$ Why would one avoid yield (a language construct) or itertools (batteries included, what Python is famous for)? \$\endgroup\$ – Thijs van Dien Aug 7 '13 at 16:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.