9

I am trying to merge sets defined in a set and this is what I have now

a = frozenset([1,3,4])
b = frozenset([1,2,3,4,5])
s = set()
s.add(a)
s.add(b)
merged = set(itertools.chain.from_iterable(s))

In practice, s may contain many frozensets. Is there better ways to do it? It feels like a reduce case, but

from functools import reduce
merged = reduce(|, s)

doesn't work.

Also

merged = reduce(set.add, s)

doesn't work because the elements of s are frozensets.

Tox
  • 834
  • 2
  • 12
  • 33
nos
  • 19,875
  • 27
  • 98
  • 134
  • 3
    `|` as a standalone function is known as [`operator.or_`](https://docs.python.org/3/library/operator.html#mapping-operators-to-functions) – Josh Lee Feb 09 '17 at 20:22

2 Answers2

12

If you have more than two frozensets, create a container (e.g., list) of them and apply a union:

listoffrozensets = [a,b,...]
frozenset().union(*listoffrozensets)
DYZ
  • 55,249
  • 10
  • 64
  • 93
  • 3
    Doesn't make a difference, really, but just use the method *directly* from the class without instantiating a useless instance: `frozenset.union` – juanpa.arrivillaga Feb 09 '17 at 20:25
  • 1
    I would say this is the "correct" way of doing this. `reduce` is likely less efficient. Anyway, in Python, `reduce` is not encouraged. This is the reason it was removed form the `built-ins` namespace in python 3. – juanpa.arrivillaga Feb 09 '17 at 20:32
  • @juanpa.arrivillaga True, `union` is about 20% faster than `reduce`, at least as reported by my `%timeit`. – DYZ Feb 09 '17 at 20:36
  • 1
    I just hit into a problem when `listoffrozensets=[]`, then I got error. But `frozenset().union(*[])` still works. – nos Feb 10 '17 at 19:08
  • @nos Good point! `frozenset().union(*listoffrozensets)` works, too. – DYZ Feb 10 '17 at 19:12
9

You can use reduce, just use the appropriate function:

>>> from functools import reduce
>>> frozenset.union
<method 'union' of 'frozenset' objects>
>>> reduce(frozenset.union, [a,b])
frozenset({1, 2, 3, 4, 5})
>>>

You were on the right track with |, but | is an operator in Python, and can't be substituted for a function. But when you want to do that, import the operator!

>>> import operator
>>> reduce(operator.or_, [a,b])
frozenset({1, 2, 3, 4, 5})
Tox
  • 834
  • 2
  • 12
  • 33
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • Note you'll need e.g. `frozenset[int].union` to avoid `Type of "union" is partially unknown` if you're `typing` – davetapley May 31 '23 at 18:27