tags:

views:

3294

answers:

11

Is the a short syntax for joining a list of lists into a single list( or iterator) in python?

For example I have a list as follows and I want to iterate over a,b and c.

x = [["a","b"], ["c"]]

The best I can come up with is as follows.

result = []
[ result.extend(el) for el in x] 

for el in result:
  print el
+6  A: 

This is known as flattening, and there are a LOT of implementations out there:

How about this, although it will only work for 1 level deep nesting:

>>> x = [["a","b"], ["c"]]
>>> for el in sum(x, []):
...     print el
...
a
b
c

From those links, apparently the most complete-fast-elegant-etc implementation is the following:

def flatten(l, ltypes=(list, tuple)):
    ltype = type(l)
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        i += 1
    return ltype(l)
Paolo Bergantino
Ah, 'sum(L,I)' is shorthand for 'reduce(plus_operator, L, I)'. That's kinda cool.
Aaron
your "most complete-elegant-etc" is not "elegant" at all!! see the docs for itertools.chain to see true elegance!
hasen j
@hasen j: I believe he means best for arbitrary nested lists. chain assumes a consistent, one-deep list of lists (which is probably all the question needs), but flatten handles things like [a,b,[c], [d,[e,f]],[[[g]]]].
Brian
+2  A: 

What you're describing is known as flattening a list, and with this new knowledge you'll be able to find many solutions to this on Google (there is no built-in flatten method). Here is one of them, from http://www.daniel-lemire.com/blog/archives/2006/05/10/flattening-lists-in-python/:

def flatten(x):
    flat = True
    ans = []
    for i in x:
        if ( i.__class__ is list):
            ans = flatten(i)
        else:
            ans.append(i)
    return ans
yjerem
+27  A: 
import itertools
a = [["a","b"], ["c"]]
print list(itertools.chain(*a))
CTT
no need to list() it! for item in itertools.chain(*a): do somethign with item
hasen j
A bit of explanation would also be nice. http://docs.python.org/library/itertools.html#itertools.chain
hasen j
A: 

Sadly, Python doesn't have a simple way to flatten lists. Try this:

def flatten(some_list):
    for element in some_list:
        if type(element) in (tuple, list):
            for item in flatten(element):
                yield item
        else:
            yield element

Which will recursively flatten a list; you can then do

result = []
[ result.extend(el) for el in x] 

for el in flatten(result):
      print el
Don Werve
+14  A: 
x = [["a","b"], ["c"]]

result = sum(x, [])
CMS
O(n^2) complexity yaaaaaay.
Aaron Gallagher
A: 

There's always reduce (being deprecated to functools):

>>> x = [ [ 'a', 'b'], ['c'] ]
>>> for el in reduce(lambda a,b: a+b, x, []):
...  print el
...
__main__:1: DeprecationWarning: reduce() not supported in 3.x; use functools.reduce()
a
b
c
>>> import functools
>>> for el in functools.reduce(lambda a,b: a+b, x, []):
...   print el
...
a
b
c
>>>

Unfortunately the plus operator for list concatenation can't be used as a function -- or fortunate, if you prefer lambdas to be ugly for improved visibility.

Aaron
GAH, I cannot believe they are deprecating it to functools. Anyway, you don't need the extra empty list, this will work just fine: reduce(lambda a,b: a+b, x)
Benson
Versions of the operators are defined as functions in the operator module, which are faster and less ugly than the lambda: "functools.reduce(operator.add, [[1,2,3],[4,5]],[])". Alternatively, just use sum()
Brian
Personally, I think the lambda way is quite pretty. :-)
Benson
+9  A: 

If you're only going one level deep, a nested comprehension will also work:

>>> x = [["a","b"], ["c"]]
>>> [inner
...     for outer in x
...         for inner in outer]
['a', 'b', 'c']

On one line, that becomes:

>>> [j for i in x for j in i]
['a', 'b', 'c']
George V. Reilly
+2  A: 

This works recursively for infinitely nested elements:

def iterFlatten(root):
    if isinstance(root, (list, tuple)):
        for element in root:
            for e in iterFlatten(element)
                yield e
    else:
        yield root

Result:

>>> b = [["a", ("b", "c")], "d"]
>>> list(iterFlatten(b))
['a', 'b', 'c', 'd']
Georg
+1  A: 

Or a recursive operation:

def flatten(input):
    ret = []
    if not isinstance(input, (list, tuple)):
        return [input]
    for i in input:
        if isinstance(i, (list, tuple)):
            ret.extend(flatten(i))
        else:
            ret.append(i)
    return ret
svhb
A: 
l = []
map(l.extend, list_of_lists)

shortest!

nate c
sum(listoflists,[]) # shorter!
recursive
A: 

I think this is the most readable way to do it:

import operator
x = [["a","b"], ["c"]]
result = reduce(operator.add, x) #["a", "b", "c"]

This only goes one level deep, though.

musicfreak
Why the downvote? Try it, it works.
musicfreak