Search code examples
pythonlistoptimizationnested-listsflatten

Flatten an irregular (arbitrarily nested) list of lists


Yes, I know this subject has been covered before:

but as far as I know, all solutions, except for one, fail on a list like [[[1, 2, 3], [4, 5]], 6], where the desired output is [1, 2, 3, 4, 5, 6] (or perhaps even better, an iterator).

The only solution I saw that works for an arbitrary nesting is found in this question:

def flatten(x):
    result = []
    for el in x:
        if hasattr(el, "__iter__") and not isinstance(el, basestring):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

Is this the best approach? Did I overlook something? Any problems?


Solution

  • Using generator functions can make your example easier to read and improve performance.

    Python 2

    Using the Iterable ABC added in 2.6:

    from collections import Iterable
    
    def flatten(xs):
        for x in xs:
            if isinstance(x, Iterable) and not isinstance(x, basestring):
                for item in flatten(x):
                    yield item
            else:
                yield x
    

    Python 3

    In Python 3, basestring is no more, but the tuple (str, bytes) gives the same effect. Also, the yield from operator returns an item from a generator one at a time.

    from collections.abc import Iterable
    
    def flatten(xs):
        for x in xs:
            if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
                yield from flatten(x)
            else:
                yield x