25

I have two lists:
[a, b, c] [d, e, f]
I want:
[a, d, b, e, c, f]

What's a simple way to do this in Python?

cs95
  • 379,657
  • 97
  • 704
  • 746
beary605
  • 802
  • 2
  • 9
  • 18

4 Answers4

35

Here is a pretty straightforward method using a list comprehension:

>>> lists = [['a', 'b', 'c'], ['d', 'e', 'f']]
>>> [x for t in zip(*lists) for x in t]
['a', 'd', 'b', 'e', 'c', 'f']

Or if you had the lists as separate variables (as in other answers):

[x for t in zip(list_a, list_b) for x in t]
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
  • 3
    +1, but as with Sven Marnach's answer, it might be worth explaining why it works: zip the lists, then flatten the result. Because it's not intuitive to most new users that "[x for t in l for x in t]" means "flatten l". – abarnert Jun 20 '12 at 18:23
  • 2
    Maybe just my preference, but this answer seems slightly less complex to me. – Aaron Johnson Jul 31 '14 at 14:55
33

One option is to use a combination of chain.from_iterable() and zip():

# Python 3:
from itertools import chain
list(chain.from_iterable(zip(list_a, list_b)))

# Python 2:
from itertools import chain, izip
list(chain.from_iterable(izip(list_a, list_b)))

Edit: As pointed out by sr2222 in the comments, this does not work well if the lists have different lengths. In that case, depending on the desired semantics, you might want to use the (far more general) roundrobin() function from the recipe section of the itertools documentation:

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    pending = len(iterables)
    nexts = cycle(iter(it).next for it in iterables)
    while pending:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            pending -= 1
            nexts = cycle(islice(nexts, pending))
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 6
    +1. Probably the best solution. But it might be worth explaining why this works: zipping gives [(a, d), (b, e), (c, f)], and then chaining flattens that into [a, d, b, e, c, f]. (Encouraging people to learn itertools is always a good thing.) – abarnert Jun 20 '12 at 17:53
  • 2
    Is this going to play nice if the lists are not of equal, or at least +/-1, length? – Silas Ray Jun 20 '12 at 17:54
  • 1
    @sr2222: Good point – it will stop on the shorter list. – Sven Marnach Jun 20 '12 at 17:57
  • 1
    @sr2222: depends what you mean by "nice". If you try it on [1, 2, 3, 4, 5] and [6, 7, 8] you'll get back [1, 6, 2, 7, 3, 8]. That's certainly _a_ reasonable answer, but it may not be the one that fits your use case. (And without knowing your use case, it's hard for anyone to say more than that.) – abarnert Jun 20 '12 at 17:57
  • 1
    @abarnert Of course it's dependent on use case, just wanted to point it out for people of the future reading this answer. :) – Silas Ray Jun 20 '12 at 17:59
  • This is an alternate implementation of roundrobin (I guess) that I made to anwer @sr2222's comment, before Sven posted his update: `list(ifilter(lambda x: x != None, chain.from_iterable(izip_longest(a, b))))` – Lauritz V. Thaulow Jun 20 '12 at 18:04
  • @lazyr: Careful with using `None` as a sentinel – it might also occur in one of the lists. You can create a unique sentinel that compares unequal to everything else by `sentinel = object()`. – Sven Marnach Jun 20 '12 at 18:14
  • `cannot import name 'izip'` with python 3.x, but [`zip`](https://stackoverflow.com/a/32659581/3719101) works fine :) – iago-lito Jun 06 '18 at 13:34
  • @iago-lito Yup, this answer was for Python 2 – updated now. – Sven Marnach Jun 06 '18 at 15:16
4

This one works only in python 2.x, but will work for lists of different lengths:

[y for x in map(None,lis_a,lis_b) for y in x]
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
2

You could do something simple using built in functions:

sum(zip(list_a, list_b),())
sblom
  • 26,911
  • 4
  • 71
  • 95
  • `TypeError: can only concatenate list (not "tuple") to list` – Makoto Jun 20 '12 at 17:51
  • 4
    This isn't the best way of joining multiple lists. It has O(n²) complexity and should be avoided. – Sven Marnach Jun 20 '12 at 17:51
  • See [Making a flat list out of list of lists in Python](http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python) for further information. – Sven Marnach Jun 20 '12 at 17:54
  • @Makoto, Type error has been fixed. – sblom Jun 20 '12 at 17:57
  • Fair enough. You may have to edit it one more time since my vote is locked. Also, if I wanted it back as an original list, I'd have to wrap it with a `list()` call. – Makoto Jun 20 '12 at 17:59
  • @sblom: No, `n` is `len(list_a)` in this case. -1 – Sven Marnach Jun 20 '12 at 18:26
  • @SvenMarnach, absolutely not. If there are 95 items in the first list, they are _not_ going to get copied 95 times (times/plus some constant), they're each going to get copied *exactly once* when `sum` creates the list from encountering `list_b`. That's not O(N^2), that O(N). I agree that it's O(N^2) on *number of sublists*, but it is _not_ O(N^2) on length of either of the sublists. – sblom Jun 20 '12 at 18:29
  • 1
    @sblom: You would be concatenating 95 pairs if the lists have 95 items. And this would mean the growing tuple would be copied in each step. This *is* O(n²) with n being the length of the input lists (assuming they have the same length). You can simply do some timings to confirm this. – Sven Marnach Jun 20 '12 at 18:43
  • @SvenMarnach, Oh, right--sorry. I accidentally shifted my argument to the scenario from the link you included earlier (and was actually even playing with timings just to make sure I was right) and lost sight of the scenario currently under discussion. Don't I feel silly. – sblom Jun 20 '12 at 18:45
  • @sblom: Never mind, I do this kind of mistake regularly. :) As a final comment, if n would be two, the preferred way of concatenating of course is `a + b`, not `sum((a, b), [])`. There is *never* a reason to use this anti-pattern. – Sven Marnach Jun 20 '12 at 18:53