It's possible to code a more general solution to this problem. The following works in Python 3.0, regardless of the level of nesting.
Let's define recursive_map
:
import collections
def recursive_map(f, iterable):
for e in iterable:
if isinstance(e, collections.Iterable):
yield recursive_map(f, e)
else:
yield f(e)
Now, the requested negation function can be coded as follows:
import functools
import operator
negate = functools.partial(recursive_map, operator.neg)
Thus, for some collection of arbitrarily nested iterables x
, we calculate its negation y
like this:
y = negate(x)
Addendum:
As noted by user chradcliffe, the above negate
function yields a generator which may contain other generators which ..., etc. To expand/evaluate all these generators, we need to apply list()
to all of them. So we define another general mapping function, this time one that works on the iterables themselves.
def recursive_iter_map(f, iterable):
def rec(e):
if isinstance(e, collections.Iterable):
return recursive_iter_map(f, e)
else:
return e
return f(map(rec, iterable))
Now,
all_lists = functools.partial(recursive_iter_map, list)
y = all_lists(negate(x))
will actually negate every element right away and return the complete list.
Note that we can regard a nested collection of iterables as a tree. Each iterable is a subtree, while non-iterables are leaves. Hence the first function I defined works on leaves, and the second function works on non-leaves.