python reduce to find the union of sets
You can use set.union
like this:
>>> lis = [{1, 2, 3, 4}, {3, 4, 5}, {7, 3, 6}]>>> set().union(*lis)set([1, 2, 3, 4, 5, 6, 7])
It's possible to do this using reduce
, but don't:
>>> reduce(set.union, lis)set([1, 2, 3, 4, 5, 6, 7])
because this reduce
takes quadratic time due to all the intermediate sets it builds and discards:
In [1]: from functools import reduceIn [2]: sets = [{x} for x in range(1000)]In [3]: %timeit set().union(*sets)40.9 µs ± 1.43 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)In [4]: %timeit reduce(set.union, sets)4.09 ms ± 587 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
That's a 100x slowdown on this test case, and it can easily be even worse.
For your code, this should do it:
set().union(*(x.nodes() for x in periodic_gs.values()))
{}
is an empty dictionary, not a set. Use set()
to create an empty set.
However, I think you are misinterpreting how reduce()
works here; x
is the previous return value of the lambda
, and y
is the next value from the sequence. Because you return a set, x
is always a set here, and you cannot use that as a key to periodic_gs
.
If you want the union of all nodes in the graph, use itertools.chain.from_iterable()
and set()
:
from itertools import chainset(chain.from_iterable(periodic_gs[key].nodes() for key in periodic_gs))
This creates one set from each of the nodes()
calls.
To use reduce()
you'd have to take into account that the first argument is always a set:
reduce(lambda res, key: res.union(periodic_gs[key].nodes()), periodic_gs, set())
I am assuming here that periodic_gs
is iterable (yielding keys) just like a regular dictionary; if not, use periodic_gs.keys()
.
A quick demo with a regular dictionary:
>>> example = {'foo': [1,2,3], 'bar': [3, 4, 1]}>>> reduce(lambda res, key: res.union(example[key]), example, set())set([1, 2, 3, 4])
There are a couple of problems with your code. The initializer you supplied to reduce
, {}
, is an empty dict
, and not a set
as you seem to be assuming, thus leading to the first type error. However, even after you fix this, there's still a bigger problem: the lambda
evaluates to a set
object containing nodes, and this set
is then used as the x
value for the next call to the lambda
, which tries to use it as as though it were a key of periodic_gs
, thereby causing the second type error. To top it all off, there's no point in iterating over the keys of a dict
if you're only going to use them to access the values; just iterate over the values in the first place! There's also no point in converting a bunch of lists to sets and then taking their union when you could just chain them all together and take the union of the result.
I would recommend rewriting the code entirely as:
set(n for val in periodic_gs.values() for n in val.nodes())