diff -r bb67b810aac1 Lib/collections/__init__.py --- a/Lib/collections/__init__.py Mon Feb 23 07:56:13 2015 -0800 +++ b/Lib/collections/__init__.py Tue Feb 24 14:31:42 2015 +0200 @@ -666,14 +666,8 @@ class Counter(dict): ''' if not isinstance(other, Counter): return NotImplemented - result = Counter() - for elem, count in self.items(): - newcount = count + other[elem] - if newcount > 0: - result[elem] = newcount - for elem, count in other.items(): - if elem not in self and count > 0: - result[elem] = count + result = Counter(self) + result += other return result def __sub__(self, other): @@ -686,8 +680,9 @@ class Counter(dict): if not isinstance(other, Counter): return NotImplemented result = Counter() + other_get = other.get for elem, count in self.items(): - newcount = count - other[elem] + newcount = count - other_get(elem, 0) if newcount > 0: result[elem] = newcount for elem, count in other.items(): @@ -704,15 +699,8 @@ class Counter(dict): ''' if not isinstance(other, Counter): return NotImplemented - result = Counter() - for elem, count in self.items(): - other_count = other[elem] - newcount = other_count if count < other_count else count - if newcount > 0: - result[elem] = newcount - for elem, count in other.items(): - if elem not in self and count > 0: - result[elem] = count + result = Counter(self) + result |= other return result def __and__(self, other): @@ -725,8 +713,9 @@ class Counter(dict): if not isinstance(other, Counter): return NotImplemented result = Counter() + other_get = other.get for elem, count in self.items(): - other_count = other[elem] + other_count = other_get(elem, 0) newcount = count if count < other_count else other_count if newcount > 0: result[elem] = newcount @@ -734,20 +723,32 @@ class Counter(dict): def __pos__(self): 'Adds an empty counter, effectively stripping negative and zero counts' - return self + Counter() + result = Counter(self) + result._keep_positive() + return result def __neg__(self): '''Subtracts from an empty counter. Strips positive and zero counts, and flips the sign on negative counts. ''' - return Counter() - self + result = Counter() + for elem, count in self.items(): + if count < 0: + result[elem] = 0 - count + return result def _keep_positive(self): '''Internal method to strip elements with a negative or zero count''' nonpositive = [elem for elem, count in self.items() if not count > 0] - for elem in nonpositive: - del self[elem] + if 2*len(nonpositive) < len(self): + for elem in nonpositive: + del self[elem] + else: + del nonpositive + positive = {elem: count for elem, count in self.items() if count > 0} + self.clear() + self.update(positive) return self def __iadd__(self, other): @@ -759,8 +760,9 @@ class Counter(dict): Counter({'b': 4, 'c': 2, 'a': 1}) ''' + self_get = self.get for elem, count in other.items(): - self[elem] += count + self[elem] = self_get(elem, 0) + count return self._keep_positive() def __isub__(self, other): @@ -772,8 +774,9 @@ class Counter(dict): Counter({'b': 2, 'a': 1}) ''' + self_get = self.get for elem, count in other.items(): - self[elem] -= count + self[elem] = self_get(elem, 0) - count return self._keep_positive() def __ior__(self, other): @@ -785,8 +788,9 @@ class Counter(dict): Counter({'b': 3, 'c': 2, 'a': 1}) ''' + self_get = self.get for elem, other_count in other.items(): - count = self[elem] + count = self_get(elem, 0) if other_count > count: self[elem] = other_count return self._keep_positive() @@ -800,8 +804,9 @@ class Counter(dict): Counter({'b': 1}) ''' + other_get = other.get for elem, count in self.items(): - other_count = other[elem] + other_count = other_get(elem, 0) if other_count < count: self[elem] = other_count return self._keep_positive()