How do I do this list manipulation in Python? it's complicated

Suppose I have this list:

[ [5, 44, 73] , [7, 21, 99], [1, 32, 100] ]

      

What's an efficient MOST way to turn it into this list?

[ 5, 7, 1, 44, 21, 32, 73, 99, 100 ] 

      

Notice I take the first of each. Then the second item from each. Of course, this function needs to be done with X elements.

I tried but I have a lot of loops and I think it is too long and complicated.

Thank.

+2


source to share


8 answers


So far, all sublists are 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 different length sublists:

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

      

-2


source


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

      



+10


source


import itertools
list(itertools.chain(*zip(*L1)))

      

If you need lists of different lengths:

import itertools
[x for x in itertools.chain(*itertools.izip_longest(*L1)) if x is not None]

      

+8


source


"One line"! = "Pythonic"

It is bad form to use a list comprehension just to implement a for loop in one line. Save expression expressions or generator expressions for the time you want the expression results. Clearest and most Pythonic to my eye (for equal length sublists):

L1 =  [ [5, 44, 73] , [7, 21, 99], [1, 32, 100] ]
L2 = []
for nextitems in zip(*L1):
    L2.extend(nextitems)

      

Of course, you could write it like:

[ L2.extend(nextitems) for nextitems in zip(*L1) ]

      

but this generates a list [None,None,...]

if the number of items in each sublist, as it extend()

returns None. And what do we do with this list? Nothing, and therefore it is immediately discarded. But the reader needs to look at this a little before realizing that this list is "built" to run extend()

for each sublist that is created.

Pythonicness is given with zip and * L1 to pass the sublists of L as args to zip. List enums are usually also considered Pythonic, but when used to create a list of things, rather than as a smart shortcut for a for loop.

+4


source


While all subscript letters have 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] ])

      

produces exactly the desired flat list.

If not all subscripts need to be the same length, what do you want when some are longer and some are shorter ...? A precise specification is needed if you need to account for such inequality.

+2


source


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

      

+1


source


Here is an O ^ 2 solution, it assumes all internal arrays are 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]

      

0


source


Simple list comprehension for 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 so 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 O (n) in complexity, where n is the total number of items.

0


source







All Articles