a list from lists

Alex Martelli aleax at aleax.it
Thu Apr 11 03:57:03 EDT 2002


mixo wrote:

> I have a list of lists (which are not of the same size but can be).
> How can I join lists to for a new list with elements from
> the list?
> 
> i.e. from,
>    listOfList = [ [1,2,3],[4,5],[6,7,8,9]]
> 
> I want to get,
>    NewList= [1,2,3,4,5,6,7,8,9]
> 
> The new list does not need to be in any particular order.

If you really have only one level of nesting,

newList = [ x for sublist in listOfLists for x in sublist ]

meets the bill.  On the "do the simplest thing that can
possibly work" principle, this is what you should do IF
only one level of nesting does indeed suffice for you.

More interesting is the ability to handle different and
arbitrary level of nesting.

First you have to decide what is an "atom", i.e., something
that's acceptable as an item in your final list.  "Anything
that's not a list" is most likely wrong (UserList should be
treated like a list, and why not tuples, ...?).  I suggest,
in Python 2.2:

def isAtom(item):
    try: iter(item)
    except: return 1   # not iterable -> surely an atom
    else:              # iterable -> atom if string-like
        try: 1 / (item in item)
        except: return 0         # normal iterable
        else: return 1           # string-like

but it makes no difference to the main issue if you want
to use some other definition such as the unpleasant:

def isAtom(item): return not isinstance(item, list)


Once you do have this, Python 2.2 makes it simple with
generators:

from __future__ import generators

def flatten(sequence, isAtom):
    if isAtom(sequence): yield sequence
    else:
        for item in sequence:
            for subitem in flatten(item, isAtom):
                yield subitem

Should you really need a list rather than (as more
often happens) an iterator,

newList = list(flatter(listOfLists))

will work,


If you need to run on Python 2.1, you can, by
producing a list directly, e.g.:


def flatten(sequence, isAtom):
    if isAtom(sequence): 
        return [ sequence ]
    else:
        return [ x for item in sequence
            for x in flatten(item, isAtom) ]


You can even do without list comprehensions
if you need to use Python 1.5.2 -- just change
any return [ x for a in b for x in a ] into the
equivalent nested loop construct:

    result = []
    for a in b:
        for x in a:
            result.append(x)
    return result


Alex




More information about the Python-list mailing list