1 collections系列

方法如下

  1 class Counter(dict):
  2     '''Dict subclass for counting hashable items.  Sometimes called a bag
  3     or multiset.  Elements are stored as dictionary keys and their counts
  4     are stored as dictionary values.
  5 
  6     >>> c = Counter('abcdeabcdabcaba')  # count elements from a string
  7 
  8     >>> c.most_common(3)                # three most common elements
  9     [('a', 5), ('b', 4), ('c', 3)]
 10     >>> sorted(c)                       # list all unique elements
 11     ['a', 'b', 'c', 'd', 'e']
 12     >>> ''.join(sorted(c.elements()))   # list elements with repetitions
 13     'aaaaabbbbcccdde'
 14     >>> sum(c.values())                 # total of all counts
 15     15
 16 
 17     >>> c['a']                          # count of letter 'a'
 18     5
 19     >>> for elem in 'shazam':           # update counts from an iterable
 20     ...     c[elem] += 1                # by adding 1 to each element's count
 21     >>> c['a']                          # now there are seven 'a'
 22     7
 23     >>> del c['b']                      # remove all 'b'
 24     >>> c['b']                          # now there are zero 'b'
 25     0
 26 
 27     >>> d = Counter('simsalabim')       # make another counter
 28     >>> c.update(d)                     # add in the second counter
 29     >>> c['a']                          # now there are nine 'a'
 30     9
 31 
 32     >>> c.clear()                       # empty the counter
 33     >>> c
 34     Counter()
 35 
 36     Note:  If a count is set to zero or reduced to zero, it will remain
 37     in the counter until the entry is deleted or the counter is cleared:
 38 
 39     >>> c = Counter('aaabbc')
 40     >>> c['b'] -= 2                     # reduce the count of 'b' by two
 41     >>> c.most_common()                 # 'b' is still in, but its count is zero
 42     [('a', 3), ('c', 1), ('b', 0)]
 43 
 44     '''
 45     # References:
 46     #   http://en.wikipedia.org/wiki/Multiset
 47     #   http://www.gnu.org/software/smalltalk/manual-base/html_node/Bag.html
 48     #   http://www.demo2s.com/Tutorial/Cpp/0380__set-multiset/Catalog0380__set-multiset.htm
 49     #   http://code.activestate.com/recipes/259174/
 50     #   Knuth, TAOCP Vol. II section 4.6.3
 51 
 52     def __init__(*args, **kwds):
 53         '''Create a new, empty Counter object.  And if given, count elements
 54         from an input iterable.  Or, initialize the count from another mapping
 55         of elements to their counts.
 56 
 57         >>> c = Counter()                           # a new, empty counter
 58         >>> c = Counter('gallahad')                 # a new counter from an iterable
 59         >>> c = Counter({'a': 4, 'b': 2})           # a new counter from a mapping
 60         >>> c = Counter(a=4, b=2)                   # a new counter from keyword args
 61 
 62         '''
 63         if not args:
 64             raise TypeError("descriptor '__init__' of 'Counter' object "
 65                             "needs an argument")
 66         self = args[0]
 67         args = args[1:]
 68         if len(args) > 1:
 69             raise TypeError('expected at most 1 arguments, got %d' % len(args))
 70         super(Counter, self).__init__()
 71         self.update(*args, **kwds)
 72 
 73     def __missing__(self, key):
 74         'The count of elements not in the Counter is zero.'
 75         # Needed so that self[missing_item] does not raise KeyError
 76         return 0
 77 
 78     def most_common(self, n=None):
 79         '''List the n most common elements and their counts from the most
 80         common to the least.  If n is None, then list all element counts.
 81 
 82         >>> Counter('abcdeabcdabcaba').most_common(3)
 83         [('a', 5), ('b', 4), ('c', 3)]
 84 
 85         '''
 86         # Emulate Bag.sortedByCount from Smalltalk
 87         if n is None:
 88             return sorted(self.iteritems(), key=_itemgetter(1), reverse=True)
 89         return _heapq.nlargest(n, self.iteritems(), key=_itemgetter(1))
 90 
 91     def elements(self):
 92         '''Iterator over elements repeating each as many times as its count.
 93 
 94         >>> c = Counter('ABCABC')
 95         >>> sorted(c.elements())
 96         ['A', 'A', 'B', 'B', 'C', 'C']
 97 
 98         # Knuth's example for prime factors of 1836:  2**2 * 3**3 * 17**1
 99         >>> prime_factors = Counter({2: 2, 3: 3, 17: 1})
100         >>> product = 1
101         >>> for factor in prime_factors.elements():     # loop over factors
102         ...     product *= factor                       # and multiply them
103         >>> product
104         1836
105 
106         Note, if an element's count has been set to zero or is a negative
107         number, elements() will ignore it.
108 
109         '''
110         # Emulate Bag.do from Smalltalk and Multiset.begin from C++.
111         return _chain.from_iterable(_starmap(_repeat, self.iteritems()))
112 
113     # Override dict methods where necessary
114 
115     @classmethod
116     def fromkeys(cls, iterable, v=None):
117         # There is no equivalent method for counters because setting v=1
118         # means that no element can have a count greater than one.
119         raise NotImplementedError(
120             'Counter.fromkeys() is undefined.  Use Counter(iterable) instead.')
121 
122     def update(*args, **kwds):
123         '''Like dict.update() but add counts instead of replacing them.
124 
125         Source can be an iterable, a dictionary, or another Counter instance.
126 
127         >>> c = Counter('which')
128         >>> c.update('witch')           # add elements from another iterable
129         >>> d = Counter('watch')
130         >>> c.update(d)                 # add elements from another counter
131         >>> c['h']                      # four 'h' in which, witch, and watch
132         4
133 
134         '''
135         # The regular dict.update() operation makes no sense here because the
136         # replace behavior results in the some of original untouched counts
137         # being mixed-in with all of the other counts for a mismash that
138         # doesn't have a straight-forward interpretation in most counting
139         # contexts.  Instead, we implement straight-addition.  Both the inputs
140         # and outputs are allowed to contain zero and negative counts.
141 
142         if not args:
143             raise TypeError("descriptor 'update' of 'Counter' object "
144                             "needs an argument")
145         self = args[0]
146         args = args[1:]
147         if len(args) > 1:
148             raise TypeError('expected at most 1 arguments, got %d' % len(args))
149         iterable = args[0] if args else None
150         if iterable is not None:
151             if isinstance(iterable, Mapping):
152                 if self:
153                     self_get = self.get
154                     for elem, count in iterable.iteritems():
155                         self[elem] = self_get(elem, 0) + count
156                 else:
157                     super(Counter, self).update(iterable) # fast path when counter is empty
158             else:
159                 self_get = self.get
160                 for elem in iterable:
161                     self[elem] = self_get(elem, 0) + 1
162         if kwds:
163             self.update(kwds)
164 
165     def subtract(*args, **kwds):
166         '''Like dict.update() but subtracts counts instead of replacing them.
167         Counts can be reduced below zero.  Both the inputs and outputs are
168         allowed to contain zero and negative counts.
169 
170         Source can be an iterable, a dictionary, or another Counter instance.
171 
172         >>> c = Counter('which')
173         >>> c.subtract('witch')             # subtract elements from another iterable
174         >>> c.subtract(Counter('watch'))    # subtract elements from another counter
175         >>> c['h']                          # 2 in which, minus 1 in witch, minus 1 in watch
176         0
177         >>> c['w']                          # 1 in which, minus 1 in witch, minus 1 in watch
178         -1
179 
180         '''
181         if not args:
182             raise TypeError("descriptor 'subtract' of 'Counter' object "
183                             "needs an argument")
184         self = args[0]
185         args = args[1:]
186         if len(args) > 1:
187             raise TypeError('expected at most 1 arguments, got %d' % len(args))
188         iterable = args[0] if args else None
189         if iterable is not None:
190             self_get = self.get
191             if isinstance(iterable, Mapping):
192                 for elem, count in iterable.items():
193                     self[elem] = self_get(elem, 0) - count
194             else:
195                 for elem in iterable:
196                     self[elem] = self_get(elem, 0) - 1
197         if kwds:
198             self.subtract(kwds)
199 
200     def copy(self):
201         'Return a shallow copy.'
202         return self.__class__(self)
203 
204     def __reduce__(self):
205         return self.__class__, (dict(self),)
206 
207     def __delitem__(self, elem):
208         'Like dict.__delitem__() but does not raise KeyError for missing values.'
209         if elem in self:
210             super(Counter, self).__delitem__(elem)
211 
212     def __repr__(self):
213         if not self:
214             return '%s()' % self.__class__.__name__
215         items = ', '.join(map('%r: %r'.__mod__, self.most_common()))
216         return '%s({%s})' % (self.__class__.__name__, items)
217 
218     # Multiset-style mathematical operations discussed in:
219     #       Knuth TAOCP Volume II section 4.6.3 exercise 19
220     #       and at http://en.wikipedia.org/wiki/Multiset
221     #
222     # Outputs guaranteed to only include positive counts.
223     #
224     # To strip negative and zero counts, add-in an empty counter:
225     #       c += Counter()
226 
227     def __add__(self, other):
228         '''Add counts from two counters.
229 
230         >>> Counter('abbb') + Counter('bcc')
231         Counter({'b': 4, 'c': 2, 'a': 1})
232 
233         '''
234         if not isinstance(other, Counter):
235             return NotImplemented
236         result = Counter()
237         for elem, count in self.items():
238             newcount = count + other[elem]
239             if newcount > 0:
240                 result[elem] = newcount
241         for elem, count in other.items():
242             if elem not in self and count > 0:
243                 result[elem] = count
244         return result
245 
246     def __sub__(self, other):
247         ''' Subtract count, but keep only results with positive counts.
248 
249         >>> Counter('abbbc') - Counter('bccd')
250         Counter({'b': 2, 'a': 1})
251 
252         '''
253         if not isinstance(other, Counter):
254             return NotImplemented
255         result = Counter()
256         for elem, count in self.items():
257             newcount = count - other[elem]
258             if newcount > 0:
259                 result[elem] = newcount
260         for elem, count in other.items():
261             if elem not in self and count < 0:
262                 result[elem] = 0 - count
263         return result
264 
265     def __or__(self, other):
266         '''Union is the maximum of value in either of the input counters.
267 
268         >>> Counter('abbb') | Counter('bcc')
269         Counter({'b': 3, 'c': 2, 'a': 1})
270 
271         '''
272         if not isinstance(other, Counter):
273             return NotImplemented
274         result = Counter()
275         for elem, count in self.items():
276             other_count = other[elem]
277             newcount = other_count if count < other_count else count
278             if newcount > 0:
279                 result[elem] = newcount
280         for elem, count in other.items():
281             if elem not in self and count > 0:
282                 result[elem] = count
283         return result
284 
285     def __and__(self, other):
286         ''' Intersection is the minimum of corresponding counts.
287 
288         >>> Counter('abbb') & Counter('bcc')
289         Counter({'b': 1})
290 
291         '''
292         if not isinstance(other, Counter):
293             return NotImplemented
294         result = Counter()
295         for elem, count in self.items():
296             other_count = other[elem]
297             newcount = count if count < other_count else other_count
298             if newcount > 0:
299                 result[elem] = newcount
300         return result
301 
302 
303 if __name__ == '__main__':
304     # verify that instances can be pickled
305     from cPickle import loads, dumps
306     Point = namedtuple('Point', 'x, y', True)
307     p = Point(x=10, y=20)
308     assert p == loads(dumps(p))
309 
310     # test and demonstrate ability to override methods
311     class Point(namedtuple('Point', 'x y')):
312         __slots__ = ()
313         @property
314         def hypot(self):
315             return (self.x ** 2 + self.y ** 2) ** 0.5
316         def __str__(self):
317             return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)
318 
319     for p in Point(3, 4), Point(14, 5/7.):
320         print p
321 
322     class Point(namedtuple('Point', 'x y')):
323         'Point class with optimized _make() and _replace() without error-checking'
324         __slots__ = ()
325         _make = classmethod(tuple.__new__)
326         def _replace(self, _map=map, **kwds):
327             return self._make(_map(kwds.get, ('x', 'y'), self))
328 
329     print Point(11, 22)._replace(x=100)
330 
331     Point3D = namedtuple('Point3D', Point._fields + ('z',))
332     print Point3D.__doc__
333 
334     import doctest
335     TestResults = namedtuple('TestResults', 'failed attempted')
336     print TestResults(*doctest.testmod())
View Code

相关文章:

  • 2021-10-11
  • 2021-07-05
  • 2021-06-09
  • 2021-05-22
  • 2021-06-14
  • 2021-10-15
猜你喜欢
  • 2021-11-10
  • 2021-11-17
  • 2021-07-29
  • 2021-06-27
  • 2021-08-09
相关资源
相似解决方案