TIMEX
TIMEX

Reputation: 272452

How do do this list manipulation in Python? This is tricky

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

Answers (8)

u0b34a0f6ae
u0b34a0f6ae

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

mmarx
mmarx

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

newacct
newacct

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

PaulMcG
PaulMcG

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

Steven Huwig
Steven Huwig

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

Amirshk
Amirshk

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

Alex Martelli
Alex Martelli

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

mthurlin
mthurlin

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

Related Questions