Reputation: 272452
Suppose I have this list:
[ [5, 44, 73] , [7, 21, 99], [1, 32, 100] ]
What is the MOST efficient way to turn it into this list?
[ 5, 7, 1, 44, 21, 32, 73, 99, 100 ]
Notice, I grab the first from each. Then the 2nd element from each. Of course, this function needs to be done with X elements.
I've tried it, but mine has many loops,and I think it's too long and complicated.
Thanks.
Upvotes: 2
Views: 1283
Reputation: 49843
A simple list comprehension to the second depth:
>>> L = [ [5, 44, 73] , [7, 21, 99], [1, 32, 100] ]
>>> [x for li in zip(*L) for x in li]
[5, 7, 1, 44, 21, 32, 73, 99, 100]
pretty nice. If the sublists are of uneven length, it is not as elegant to express:
>>> L = [ [5, 44, 73] , [7], [1, 32, 100, 101] ]
>>> [li[idx] for idx in xrange(max(map(len, L))) for li in L if idx < len(li)]
[5, 7, 1, 44, 32, 73, 100, 101]
These solutions are of complexity O(n), where n is the total number of elements.
Upvotes: 0
Reputation: 150
As long as all the sublists are of the same length:
lst = [[5, 44, 73] , [7, 21, 99], [1, 32, 100]]
list(reduce(lambda l, r: l + r, zip(*lst)))
Edit: This will work with sublists of different lengths:
lst = [[5, 44, 73, 23] , [7, 21, 99], [1, 32, 100]]
list(filter(lambda p: p is not None, reduce(lambda x, y: x + y, map(None, *lst))))
Upvotes: -2
Reputation: 122538
>>> L1 = [ [5, 44, 73] , [7, 21, 99], [1, 32, 100] ]
>>> L2 = list(sum(zip(*L1), ()))
>>> L2
[5, 7, 1, 44, 21, 32, 73, 99, 100]
Upvotes: 1
Reputation: 63802
"One-liner" != "Pythonic"
It is bad form to use a list comprehension just to implement a for loop in one line. Save the list expressions or generator expressions for times when you want the results of the expression. The clearest and most Pythonic to my eye is (for sublists of equal length):
L1 = [ [5, 44, 73] , [7, 21, 99], [1, 32, 100] ]
L2 = []
for nextitems in zip(*L1):
L2.extend(nextitems)
Sure you could write this as:
[ L2.extend(nextitems) for nextitems in zip(*L1) ]
but this generates a list of [None,None,...]
as long as the number of items in each sublist, since extend()
returns None. And what are we doing with this list? Nothing, and so it gets discarded immediately. But the reader has to look at this for a bit before realizing that this list is "built" for the purpose of running extend()
on each created sublist.
The Pythonicness is given by the use of zip and *L1 to pass the sublists of L as args to zip. List comprehensions are generally regarded as Pythonic too, but when they are used for the purpose of creating a list of things, not as a clever shortcut for a for loop.
Upvotes: 4
Reputation: 20804
import itertools
list(itertools.chain(*zip(*L1)))
If you need lists of varying length:
import itertools
[x for x in itertools.chain(*itertools.izip_longest(*L1)) if x is not None]
Upvotes: 8
Reputation: 8258
Here is an O^2 solution, it assumes all the inner arrays are of the same length
parent = [ [5, 44, 73] , [7, 21, 99], [1, 32, 100] ]
final = []
for i in range(len(parent[0])):
for x in range(len(parent)):
final.append(parent[x][i])
print final # [5, 7, 1, 44, 21, 32, 73, 99, 100]
Upvotes: 0
Reputation: 882851
As long as all sublists are the same length:
def flattener(nestedlist):
if not nestedlist: return []
return [ x for i in range(len(nestedlist[0]))
for x in [sublist[i] for sublist in nestedlist]
]
For example,
print flattener([ [5, 44, 73] , [7, 21, 99], [1, 32, 100] ])
emits exactly the flat list you desire.
If not all sublist need be the same length, what do you want to happen when some are longer, some shorter...? A precise spec is needed if you need to take such inequality into account.
Upvotes: 2
Reputation: 27315
>>> L1 = [ [5, 44, 73] , [7, 21, 99], [1, 32, 100] ]
>>> L2 = []
>>> map(L2.extend, zip(*L1))
>>> L2
[5, 7, 1, 44, 21, 32, 73, 99, 100]
Upvotes: 10