deepflatten

class iteration_utilities.deepflatten(iterable, depth=-1, types=None, ignore=None)

Flatten an iterable with given depth.

Parameters:

iterable : iterable

Any iterable to flatten.

depth : int or None, optional

Flatten depth levels of nesting or all if depth=-1. Default is -1.

Note

If the depth is known this significantly speeds up the function!

types : type, tuple of types, optional

Which types should be flattened. If not given it flattens all items if iter(item) does not throw a TypeError.

Note

If the types are known this significantly speeds up the function but only if the depth is unknown.

ignore : type, iterable of types or None, optional

The types which should not be flattened. If not given all types are flattened.

Returns:

flattened_iterable : generator

The iterable with the depth level of nesting flattened.

Examples

To flatten a given depth:

>>> from iteration_utilities import deepflatten, EQ_PY2
>>> list(deepflatten([1, [1,2], [[1,2]], [[[1,2]]]], depth=1))
[1, 1, 2, [1, 2], [[1, 2]]]

To completly flatten it:

>>> list(deepflatten([1, [1,2], [[1,2]], [[[1,2]]]]))
[1, 1, 2, 1, 2, 1, 2]

To ignore for example dictionaries:

>>> # Only the keys of a dictionary will be kept with deepflatten.
>>> list(deepflatten([1, 2, [1,2],  {1: 10, 2: 10}]))
[1, 2, 1, 2, 1, 2]
>>> list(deepflatten([1, 2, [1,2],  {1: 10, 2: 10}], ignore=dict))
[1, 2, 1, 2, {1: 10, 2: 10}]

In this case we could have also chosen only to flatten the lists:

>>> list(deepflatten([1, 2, [1,2],  {1: 10, 2: 10}], types=list))
[1, 2, 1, 2, {1: 10, 2: 10}]

Warning

If the iterable contains recursive iterable objects (i.e. UserString) one either needs to set ignore or a depth that is not None. Otherwise this will raise an RecursionError (or RuntimeError on older Python versions) because each item in a UserString is itself a UserString, even if it has a length of 1! The builtin strings (str, bytes, unicode) are special cased, but only the exact types because subtypes might implement custom not-recusive __iter__ methods. This means that these won’t run into the infinite recursion, but subclasses might.

See for example:

>>> if EQ_PY2:
...     from UserString import UserString
... else:
...     from collections import UserString
>>> list(deepflatten([1, 2, [1,2], UserString('abc')], depth=1))
[1, 2, 1, 2, 'a', 'b', 'c']
>>> list(deepflatten([1, 2, [1,2], UserString('abc')], ignore=UserString))
[1, 2, 1, 2, 'abc']

For Python2 you should ignore basestring instead of str.

This function is roughly (it’s missing some of the complicated details of the actual function) equivalent to this python function:

def deepflatten(iterable, depth=None, types=None, ignore=None):
    if depth is None:
        depth = float('inf')
    if depth == -1:
        yield iterable
    else:
        for x in iterable:
            if ignore is not None and isinstance(x, ignore):
                yield x
            if types is None:
                try:
                    iter(x)
                except TypeError:
                    yield x
                else:
                    for item in deepflatten(x, depth - 1, types, ignore):
                        yield item
            elif not isinstance(x, types):
                yield x
            else:
                for item in deepflatten(x, depth - 1, types, ignore):
                    yield item
currentdepth

(int) The current depth inside the iterable (readonly).

New in version 0.6.

depth

(int) Up to this depth the iterable is flattened (readonly).

New in version 0.6.

ignore

(type or tuple thereof) The types that are not flattened (readonly).

New in version 0.6.

types

(type or tuple thereof) The types to flatten or None if deepflatten attempts to flatten every type (readonly).

New in version 0.6.