Reputation: 3396
What's the best way (in terms of readability and efficiency) of finding the union of a list of Counters?
For example, my list might look like this:
counters = [Counter({'a': 6, 'b': 3, 'c': 1}),
Counter({'a': 2, 'b': 5}),
Counter({'a': 4, 'b': 4}),
...]
I want to calculate the union, i.e. counters[0] | counters[1] | counters[2] | ...
.
One way of doing it would be this:
def counter_union(iterable):
return functools.reduce(operator.or_, iterable, Counter())
Is there a better approach?
Upvotes: 4
Views: 2771
Reputation: 3396
user2357112 and Tim's comments made me realize that if you are going to use reduce
, you should at least use operator.ior
, not operator.or_
. In Python 3.3+, this will avoid creating a new counter for every iteration.
def counter_union(iterable):
return functools.reduce(operator.ior, iterable, Counter())
Upvotes: 3
Reputation: 70735
Goodness, when did Python programmers become afraid of easy loops? LOL.
result = Counter()
for c in counters:
result |= c
There really aren't prizes in real life for squashing things into as few characters as theoretically possible. Well, ya, there are in Perl, but not in Python ;-)
Later: pursuant to user2357112's comment, starting with Python 3.3 the code above will do "in place" unions into result
. That is, result
is truly reused, possibly growing larger on each iteration.
In any spelling of
counters[0] | counters[1] | counters[2] | ...
instead, the entire partial result so far keeps getting thrown away when the next partial result is computed. That may - or may not - be a lot slower.
Upvotes: 7
Reputation: 67138
I think a loop is much more readable:
def counter_union(iterable):
union = Counter()
for counter in counters:
union |= counter
return union
Upvotes: 2