deepflatten

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

Flatten an iterable with given depth.

Parameters:
iterableiterable

Any iterable to flatten.

depthint 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!

typestype, 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 given this significantly speeds up the function but only if the depth is unknown.

ignoretype, iterable of types or None, optional

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

Returns:
flattened_iterablegenerator

The iterable with the depth level of nesting flattened.

Examples

To flatten a given depth:

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

To completely 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-recursive __iter__ methods. This means that these won’t run into the infinite recursion, but subclasses might.

See for example:

>>> 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']

This function is roughly (it’s missing some of the complicated details and performance optimizations 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:
                    yield from deepflatten(x, depth - 1, types, ignore)
            elif not isinstance(x, types):
                yield x
            else:
                yield from deepflatten(x, depth - 1, types, ignore)
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.