Question

List Comprehension for me seems to be like the opaque block of granite that regular expressions are for me. I need pointers.

Say, I have a 2D list:

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

I would like to merge this either into one long list

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

or into a string with separators:

s = "0,1,2,3,4,5,6,7,8"

Really, I'd like to know how to do both.

Was it helpful?

Solution

Like so:

[ item for innerlist in outerlist for item in innerlist ]

Turning that directly into a string with separators:

','.join(str(item) for innerlist in outerlist for item in innerlist)

Yes, the order of 'for innerlist in outerlist' and 'for item in innerlist' is correct. Even though the "body" of the loop is at the start of the listcomp, the order of nested loops (and 'if' clauses) is still the same as when you would write the loop out:

for innerlist in outerlist:
    for item in innerlist:
        ...

OTHER TIPS

Try that:

li=[[0,1,2],[3,4,5],[6,7,8]]
li2 = [ y for x in li for y in x]

You can read it like this:
Give me the list of every ys.
The ys come from the xs.
The xs come from li.

To map that in a string:

','.join(map(str,li2))

There's a couple choices. First, you can just create a new list and add the contents of each list to it:

li2 = []
for sublist in li:
    li2.extend(sublist)

Alternately, you can use the itertools module's chain function, which produces an iterable containing all the items in multiple iterables:

import itertools
li2 = list(itertools.chain(*li))

If you take this approach, you can produce the string without creating an intermediate list:

s = ",".join(itertools.chain(*li))

My favorite, and the shortest one, is this:

li2 = sum(li, [])

and

s = ','.join(li2)

EDIT: use sum instead of reduce, (thanks Thomas Wouters!)

To make it a flattened list use either:

  1. http://code.activestate.com/recipes/121294/
  2. http://code.activestate.com/recipes/363051/

Then, join to make it a string.

For the second one, there is a built-in string method to do that :

>>> print ','.join(str(x) for x in li2)
"0,1,2,3,4,5,6,7,8"

For the first one, you can use join within a comprehension list :

>>> print ",".join([",".join(str(x) for x in li])
"0,1,2,3,4,5,6,7,8"

But it's easier to use itertools.flatten :

>>> import itertools
>>> print itertools.flatten(li)
[0,1,2,3,4,5,6,7,8]
>>> print ",".join(str(x) for x in itertools.flatten(li))
"0,1,2,3,4,5,6,7,8"

N.B : itertools is a module that help you to deal with common tasks with iterators such as list, tuples or string... It's handy because it does not store a copy of the structure you're working on but process the items one by one.

EDIT : funny, I am learning plenty of way to do it. Who said that there was only one good way to do it ?

There are many ways to do this problem. I like Numpy's tools because it is normally already imported in everything I do. However, if you aren't using Numpy for anything else this probably isn't a good method.

import numpy
li = [[0,1,2],[3,4,5],[6,7,8]]
li2=li[0] #first element of array to merge
i=1 
while i<len(li):
    li2=numpy.concatenate((li2,li[i]))
    i+=1
print li2

This would print [0 1 2 3 4 5 6 7 8] and then you can convert this into your string too.

import itertools
itertools.flatten( li )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top