Welcome, guest | Sign In | My Account | Store | Cart

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

Python, 10 lines
 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

5 comments

Matthew Wood 12 years, 8 months ago  # | flag

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.

Gabriel Barta 12 years, 8 months ago  # | flag

@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.

Aaron Gallagher 12 years, 7 months ago  # | flag

-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.

marlonamor (author) 12 years, 7 months ago  # | flag

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

marlonamor (author) 12 years, 7 months ago  # | flag

Just remove the exception object 'TypeError'

Created by marlonamor on Tue, 14 Apr 2009 (MIT)
Python recipes (4591)
marlonamor's recipes (2)

Required Modules

  • (none specified)

Other Information and Tasks