ActiveState Code

Recipe 576719: Flattened List


This flattenizes any nested level list. I couln't find this in itertools module so I wrote it. Python 3 may be required.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def deepFlatten(lista):
    '''
    >>> list(deepFlatten([1,2,[], [1], 3, [4, [5,6]], 7, 'oi', None])) => [1, 2, 1, 3, 4, 5, 6, 7, 'o', 'i', None]
    '''
    try:
        for item in lista:
            for one in deepFlatten(item):
                yield one
    except:
        yield lista

Comments

  1. 1. At 3:16 p.m. on 14 apr 2009, Matthew Wood said:

    The best I've been able to come up with thus far is:

    def deep_flatten(iter_):
        if hasattr(iter_, '__iter__') or hasattr(iter, '__getitem__'):
            for item in iter_:
                for elem in deep_flatten(item):
                    yield elem
        else:
            yield iter_
    

    The "best" solution would seem to me to be:

    def deep_flatten2(iter_):
        try:
            for item in iter_:
                for elem in deep_flatten2(item):
                    yield elem
        except TypeError:
            yield iter_
    

    but I keep getting the following warnings:

    Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in <type 'exceptions.TypeError'> ignored

    Anyone know why I get that error? Even with just 2 "levels" of flattening to do, I hit a recursion depth error, which seems incorrect.

  2. 2. At 10:31 p.m. on 14 apr 2009, Gabriel Barta said:

    @Matthew Wood:

    For the same reason that the str special case is in the recipe. Iterating a string produces strings of length 1. Since 'o' is an iterable of length 1, deep_flatten('o') will keep stepping into the try clause without ever generating a TypeError.

  3. 3. At 4:28 a.m. on 21 apr 2009, Aaron Gallagher said:

    -1 for not working in the general case.

    By checking types, you limit yourself to a finite number of classes that will "work" here. Without using ABCs (which won't always work) you have to limit yourself to either a finite number of stringlike objects, or a finite number of non-stringlike iterables.

    You know what works waaay better than this recipe? Not being in a situation where you have to flatten arbitrarily-nested iterables in the first place. It's less common and more easily-avoidable than you think, and then you don't get into awful situations like this.

  4. 4. At 6:39 p.m. on 27 apr 2009, marlonamor (the author) said:

    Good points so we can recall the solution from Matthew with a small modification:

    def deepFlatten(lista): try: for item in lista: for one in deepFlatten(item): yield one except: yield lista

  5. 5. At 6:44 p.m. on 27 apr 2009, marlonamor (the author) said:

    Just remove the exception object 'TypeError'

Sign in to comment