11

How would you iterate through a list of lists, such as:

[[1,2,3,4], [5,6], [7,8,9]]

and construct a new list by grabbing the first item of each list, then the second, etc. So the above becomes this:

[1, 5, 7, 2, 6, 8, 3, 9, 4]
0

5 Answers 5

12

You can use a list comprehension along with itertools.izip_longest (or zip_longest in Python 3)

from itertools import izip_longest
a = [[1,2,3,4], [5,6], [7,8,9]]
[i for sublist in izip_longest(*a) for i in sublist if i is not None]
# [1, 5, 7, 2, 6, 8, 3, 9, 4]
Sign up to request clarification or add additional context in comments.

8 Comments

You will lose any 0's, you should check for None
Your example would be even better if you renamed j in a more readable way, like result_with_holes or something.
In Python 3 the name has changed to zip_longest.
@9000 Changed it. Thanks :-)
If you want to be fancy, this is equivalent to list(filter(lambda x: x is not None, chain(*zip_longest(*a))))
|
6

As long as you know that None will not appear, you can take advantage of how map() works with no function:

outlist = [y for sub in map(None, *inlist) for y in sub if not y is None]

Comments

4

DRY: itertools has a recipe that sounds right for this task: roundrobin

from itertools import cycle, islice

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))

l = [[1,2,3,4], [5,6], [7,8,9]]

print (list(roundrobin(*l)))
#[1, 5, 7, 2, 6, 8, 3, 9, 4]

4 Comments

This is for Python 2 only, the Python 3 version can be found here.
You are right, @pp_, python 2 uses the attribute next and python 3 uses __next__.
I think next(iter(it)) would work for both, right?
@Paul: Yes, but then you'd need to use functools.partial or a lambda, in this code.
1

You can do it manually without using any import if you don't want to.

Keep N different counters where n is the number of lists in your list and increment them whenever you add a new element from that sublists. While adding them you should control that respective sets counter must be the minimum of all other counters if all lists have remaining elements.When you add the last element of list you can increment its counter to something like 9999 to protect our minimum rule.

This will be harder to implement and I do not suggest you to implement in this way but this is also a possibility if you do not want to import anything or want to have a programming challenge for your level.

Comments

0

Solutions that filter out None won't work if None is a value from the sublists that you would like to keep. To fix this, you can do a list comprehension that iterates over the indices of the longest sublist, and only adds sublist items if the index is in range.

a = [[1,2,3,4],[5,6,None],[7,8,9]]
range_longest = range(max(map(len, a)))
[sublist[i] for i in range_longest for sublist in a if i < len(sublist)]
# [1, 5, 7, 2, 6, 8, 3, None, 9, 4]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.