PageRenderTime 51ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/External.LCA_RESTRICTED/Languages/IronPython/27/Lib/collections.py

http://github.com/IronLanguages/main
Python | 742 lines | 712 code | 10 blank | 20 comment | 28 complexity | 7f1b871d9b865679610eccccb16bd79d MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. '''This module implements specialized container datatypes providing
  2. alternatives to Python's general purpose built-in containers, dict,
  3. list, set, and tuple.
  4. * namedtuple factory function for creating tuple subclasses with named fields
  5. * deque list-like container with fast appends and pops on either end
  6. * Counter dict subclass for counting hashable objects
  7. * OrderedDict dict subclass that remembers the order entries were added
  8. * defaultdict dict subclass that calls a factory function to supply missing values
  9. '''
  10. __all__ = ['Counter', 'deque', 'defaultdict', 'namedtuple', 'OrderedDict']
  11. # For bootstrapping reasons, the collection ABCs are defined in _abcoll.py.
  12. # They should however be considered an integral part of collections.py.
  13. from _abcoll import *
  14. import _abcoll
  15. __all__ += _abcoll.__all__
  16. from _collections import deque, defaultdict
  17. from operator import itemgetter as _itemgetter, eq as _eq
  18. from keyword import iskeyword as _iskeyword
  19. import sys as _sys
  20. import heapq as _heapq
  21. from itertools import repeat as _repeat, chain as _chain, starmap as _starmap
  22. from itertools import imap as _imap
  23. try:
  24. from thread import get_ident as _get_ident
  25. except ImportError:
  26. from dummy_thread import get_ident as _get_ident
  27. ################################################################################
  28. ### OrderedDict
  29. ################################################################################
  30. class OrderedDict(dict):
  31. 'Dictionary that remembers insertion order'
  32. # An inherited dict maps keys to values.
  33. # The inherited dict provides __getitem__, __len__, __contains__, and get.
  34. # The remaining methods are order-aware.
  35. # Big-O running times for all methods are the same as regular dictionaries.
  36. # The internal self.__map dict maps keys to links in a doubly linked list.
  37. # The circular doubly linked list starts and ends with a sentinel element.
  38. # The sentinel element never gets deleted (this simplifies the algorithm).
  39. # Each link is stored as a list of length three: [PREV, NEXT, KEY].
  40. def __init__(*args, **kwds):
  41. '''Initialize an ordered dictionary. The signature is the same as
  42. regular dictionaries, but keyword arguments are not recommended because
  43. their insertion order is arbitrary.
  44. '''
  45. if not args:
  46. raise TypeError("descriptor '__init__' of 'OrderedDict' object "
  47. "needs an argument")
  48. self = args[0]
  49. args = args[1:]
  50. if len(args) > 1:
  51. raise TypeError('expected at most 1 arguments, got %d' % len(args))
  52. try:
  53. self.__root
  54. except AttributeError:
  55. self.__root = root = [] # sentinel node
  56. root[:] = [root, root, None]
  57. self.__map = {}
  58. self.__update(*args, **kwds)
  59. def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
  60. 'od.__setitem__(i, y) <==> od[i]=y'
  61. # Setting a new item creates a new link at the end of the linked list,
  62. # and the inherited dictionary is updated with the new key/value pair.
  63. if key not in self:
  64. root = self.__root
  65. last = root[0]
  66. last[1] = root[0] = self.__map[key] = [last, root, key]
  67. return dict_setitem(self, key, value)
  68. def __delitem__(self, key, dict_delitem=dict.__delitem__):
  69. 'od.__delitem__(y) <==> del od[y]'
  70. # Deleting an existing item uses self.__map to find the link which gets
  71. # removed by updating the links in the predecessor and successor nodes.
  72. dict_delitem(self, key)
  73. link_prev, link_next, _ = self.__map.pop(key)
  74. link_prev[1] = link_next # update link_prev[NEXT]
  75. link_next[0] = link_prev # update link_next[PREV]
  76. def __iter__(self):
  77. 'od.__iter__() <==> iter(od)'
  78. # Traverse the linked list in order.
  79. root = self.__root
  80. curr = root[1] # start at the first node
  81. while curr is not root:
  82. yield curr[2] # yield the curr[KEY]
  83. curr = curr[1] # move to next node
  84. def __reversed__(self):
  85. 'od.__reversed__() <==> reversed(od)'
  86. # Traverse the linked list in reverse order.
  87. root = self.__root
  88. curr = root[0] # start at the last node
  89. while curr is not root:
  90. yield curr[2] # yield the curr[KEY]
  91. curr = curr[0] # move to previous node
  92. def clear(self):
  93. 'od.clear() -> None. Remove all items from od.'
  94. root = self.__root
  95. root[:] = [root, root, None]
  96. self.__map.clear()
  97. dict.clear(self)
  98. # -- the following methods do not depend on the internal structure --
  99. def keys(self):
  100. 'od.keys() -> list of keys in od'
  101. return list(self)
  102. def values(self):
  103. 'od.values() -> list of values in od'
  104. return [self[key] for key in self]
  105. def items(self):
  106. 'od.items() -> list of (key, value) pairs in od'
  107. return [(key, self[key]) for key in self]
  108. def iterkeys(self):
  109. 'od.iterkeys() -> an iterator over the keys in od'
  110. return iter(self)
  111. def itervalues(self):
  112. 'od.itervalues -> an iterator over the values in od'
  113. for k in self:
  114. yield self[k]
  115. def iteritems(self):
  116. 'od.iteritems -> an iterator over the (key, value) pairs in od'
  117. for k in self:
  118. yield (k, self[k])
  119. update = MutableMapping.update
  120. __update = update # let subclasses override update without breaking __init__
  121. __marker = object()
  122. def pop(self, key, default=__marker):
  123. '''od.pop(k[,d]) -> v, remove specified key and return the corresponding
  124. value. If key is not found, d is returned if given, otherwise KeyError
  125. is raised.
  126. '''
  127. if key in self:
  128. result = self[key]
  129. del self[key]
  130. return result
  131. if default is self.__marker:
  132. raise KeyError(key)
  133. return default
  134. def setdefault(self, key, default=None):
  135. 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
  136. if key in self:
  137. return self[key]
  138. self[key] = default
  139. return default
  140. def popitem(self, last=True):
  141. '''od.popitem() -> (k, v), return and remove a (key, value) pair.
  142. Pairs are returned in LIFO order if last is true or FIFO order if false.
  143. '''
  144. if not self:
  145. raise KeyError('dictionary is empty')
  146. key = next(reversed(self) if last else iter(self))
  147. value = self.pop(key)
  148. return key, value
  149. def __repr__(self, _repr_running={}):
  150. 'od.__repr__() <==> repr(od)'
  151. call_key = id(self), _get_ident()
  152. if call_key in _repr_running:
  153. return '...'
  154. _repr_running[call_key] = 1
  155. try:
  156. if not self:
  157. return '%s()' % (self.__class__.__name__,)
  158. return '%s(%r)' % (self.__class__.__name__, self.items())
  159. finally:
  160. del _repr_running[call_key]
  161. def __reduce__(self):
  162. 'Return state information for pickling'
  163. items = [[k, self[k]] for k in self]
  164. inst_dict = vars(self).copy()
  165. for k in vars(OrderedDict()):
  166. inst_dict.pop(k, None)
  167. if inst_dict:
  168. return (self.__class__, (items,), inst_dict)
  169. return self.__class__, (items,)
  170. def copy(self):
  171. 'od.copy() -> a shallow copy of od'
  172. return self.__class__(self)
  173. @classmethod
  174. def fromkeys(cls, iterable, value=None):
  175. '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
  176. If not specified, the value defaults to None.
  177. '''
  178. self = cls()
  179. for key in iterable:
  180. self[key] = value
  181. return self
  182. def __eq__(self, other):
  183. '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
  184. while comparison to a regular mapping is order-insensitive.
  185. '''
  186. if isinstance(other, OrderedDict):
  187. return dict.__eq__(self, other) and all(_imap(_eq, self, other))
  188. return dict.__eq__(self, other)
  189. def __ne__(self, other):
  190. 'od.__ne__(y) <==> od!=y'
  191. return not self == other
  192. # -- the following methods support python 3.x style dictionary views --
  193. def viewkeys(self):
  194. "od.viewkeys() -> a set-like object providing a view on od's keys"
  195. return KeysView(self)
  196. def viewvalues(self):
  197. "od.viewvalues() -> an object providing a view on od's values"
  198. return ValuesView(self)
  199. def viewitems(self):
  200. "od.viewitems() -> a set-like object providing a view on od's items"
  201. return ItemsView(self)
  202. ################################################################################
  203. ### namedtuple
  204. ################################################################################
  205. _class_template = '''\
  206. class {typename}(tuple):
  207. '{typename}({arg_list})'
  208. __slots__ = ()
  209. _fields = {field_names!r}
  210. def __new__(_cls, {arg_list}):
  211. 'Create new instance of {typename}({arg_list})'
  212. return _tuple.__new__(_cls, ({arg_list}))
  213. @classmethod
  214. def _make(cls, iterable, new=tuple.__new__, len=len):
  215. 'Make a new {typename} object from a sequence or iterable'
  216. result = new(cls, iterable)
  217. if len(result) != {num_fields:d}:
  218. raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result))
  219. return result
  220. def __repr__(self):
  221. 'Return a nicely formatted representation string'
  222. return '{typename}({repr_fmt})' % self
  223. def _asdict(self):
  224. 'Return a new OrderedDict which maps field names to their values'
  225. return OrderedDict(zip(self._fields, self))
  226. def _replace(_self, **kwds):
  227. 'Return a new {typename} object replacing specified fields with new values'
  228. result = _self._make(map(kwds.pop, {field_names!r}, _self))
  229. if kwds:
  230. raise ValueError('Got unexpected field names: %r' % kwds.keys())
  231. return result
  232. def __getnewargs__(self):
  233. 'Return self as a plain tuple. Used by copy and pickle.'
  234. return tuple(self)
  235. __dict__ = _property(_asdict)
  236. def __getstate__(self):
  237. 'Exclude the OrderedDict from pickling'
  238. pass
  239. {field_defs}
  240. '''
  241. _repr_template = '{name}=%r'
  242. _field_template = '''\
  243. {name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}')
  244. '''
  245. def namedtuple(typename, field_names, verbose=False, rename=False):
  246. """Returns a new subclass of tuple with named fields.
  247. >>> Point = namedtuple('Point', ['x', 'y'])
  248. >>> Point.__doc__ # docstring for the new class
  249. 'Point(x, y)'
  250. >>> p = Point(11, y=22) # instantiate with positional args or keywords
  251. >>> p[0] + p[1] # indexable like a plain tuple
  252. 33
  253. >>> x, y = p # unpack like a regular tuple
  254. >>> x, y
  255. (11, 22)
  256. >>> p.x + p.y # fields also accessible by name
  257. 33
  258. >>> d = p._asdict() # convert to a dictionary
  259. >>> d['x']
  260. 11
  261. >>> Point(**d) # convert from a dictionary
  262. Point(x=11, y=22)
  263. >>> p._replace(x=100) # _replace() is like str.replace() but targets named fields
  264. Point(x=100, y=22)
  265. """
  266. # Validate the field names. At the user's option, either generate an error
  267. # message or automatically replace the field name with a valid name.
  268. if isinstance(field_names, basestring):
  269. field_names = field_names.replace(',', ' ').split()
  270. field_names = map(str, field_names)
  271. typename = str(typename)
  272. if rename:
  273. seen = set()
  274. for index, name in enumerate(field_names):
  275. if (not all(c.isalnum() or c=='_' for c in name)
  276. or _iskeyword(name)
  277. or not name
  278. or name[0].isdigit()
  279. or name.startswith('_')
  280. or name in seen):
  281. field_names[index] = '_%d' % index
  282. seen.add(name)
  283. for name in [typename] + field_names:
  284. if type(name) != str:
  285. raise TypeError('Type names and field names must be strings')
  286. if not all(c.isalnum() or c=='_' for c in name):
  287. raise ValueError('Type names and field names can only contain '
  288. 'alphanumeric characters and underscores: %r' % name)
  289. if _iskeyword(name):
  290. raise ValueError('Type names and field names cannot be a '
  291. 'keyword: %r' % name)
  292. if name[0].isdigit():
  293. raise ValueError('Type names and field names cannot start with '
  294. 'a number: %r' % name)
  295. seen = set()
  296. for name in field_names:
  297. if name.startswith('_') and not rename:
  298. raise ValueError('Field names cannot start with an underscore: '
  299. '%r' % name)
  300. if name in seen:
  301. raise ValueError('Encountered duplicate field name: %r' % name)
  302. seen.add(name)
  303. # Fill-in the class template
  304. class_definition = _class_template.format(
  305. typename = typename,
  306. field_names = tuple(field_names),
  307. num_fields = len(field_names),
  308. arg_list = repr(tuple(field_names)).replace("'", "")[1:-1],
  309. repr_fmt = ', '.join(_repr_template.format(name=name)
  310. for name in field_names),
  311. field_defs = '\n'.join(_field_template.format(index=index, name=name)
  312. for index, name in enumerate(field_names))
  313. )
  314. if verbose:
  315. print class_definition
  316. # Execute the template string in a temporary namespace and support
  317. # tracing utilities by setting a value for frame.f_globals['__name__']
  318. namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
  319. OrderedDict=OrderedDict, _property=property, _tuple=tuple)
  320. try:
  321. exec class_definition in namespace
  322. except SyntaxError as e:
  323. raise SyntaxError(e.message + ':\n' + class_definition)
  324. result = namespace[typename]
  325. # For pickling to work, the __module__ variable needs to be set to the frame
  326. # where the named tuple is created. Bypass this step in environments where
  327. # sys._getframe is not defined (Jython for example) or sys._getframe is not
  328. # defined for arguments greater than 0 (IronPython).
  329. try:
  330. result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
  331. except (AttributeError, ValueError):
  332. pass
  333. return result
  334. ########################################################################
  335. ### Counter
  336. ########################################################################
  337. class Counter(dict):
  338. '''Dict subclass for counting hashable items. Sometimes called a bag
  339. or multiset. Elements are stored as dictionary keys and their counts
  340. are stored as dictionary values.
  341. >>> c = Counter('abcdeabcdabcaba') # count elements from a string
  342. >>> c.most_common(3) # three most common elements
  343. [('a', 5), ('b', 4), ('c', 3)]
  344. >>> sorted(c) # list all unique elements
  345. ['a', 'b', 'c', 'd', 'e']
  346. >>> ''.join(sorted(c.elements())) # list elements with repetitions
  347. 'aaaaabbbbcccdde'
  348. >>> sum(c.values()) # total of all counts
  349. 15
  350. >>> c['a'] # count of letter 'a'
  351. 5
  352. >>> for elem in 'shazam': # update counts from an iterable
  353. ... c[elem] += 1 # by adding 1 to each element's count
  354. >>> c['a'] # now there are seven 'a'
  355. 7
  356. >>> del c['b'] # remove all 'b'
  357. >>> c['b'] # now there are zero 'b'
  358. 0
  359. >>> d = Counter('simsalabim') # make another counter
  360. >>> c.update(d) # add in the second counter
  361. >>> c['a'] # now there are nine 'a'
  362. 9
  363. >>> c.clear() # empty the counter
  364. >>> c
  365. Counter()
  366. Note: If a count is set to zero or reduced to zero, it will remain
  367. in the counter until the entry is deleted or the counter is cleared:
  368. >>> c = Counter('aaabbc')
  369. >>> c['b'] -= 2 # reduce the count of 'b' by two
  370. >>> c.most_common() # 'b' is still in, but its count is zero
  371. [('a', 3), ('c', 1), ('b', 0)]
  372. '''
  373. # References:
  374. # http://en.wikipedia.org/wiki/Multiset
  375. # http://www.gnu.org/software/smalltalk/manual-base/html_node/Bag.html
  376. # http://www.demo2s.com/Tutorial/Cpp/0380__set-multiset/Catalog0380__set-multiset.htm
  377. # http://code.activestate.com/recipes/259174/
  378. # Knuth, TAOCP Vol. II section 4.6.3
  379. def __init__(*args, **kwds):
  380. '''Create a new, empty Counter object. And if given, count elements
  381. from an input iterable. Or, initialize the count from another mapping
  382. of elements to their counts.
  383. >>> c = Counter() # a new, empty counter
  384. >>> c = Counter('gallahad') # a new counter from an iterable
  385. >>> c = Counter({'a': 4, 'b': 2}) # a new counter from a mapping
  386. >>> c = Counter(a=4, b=2) # a new counter from keyword args
  387. '''
  388. if not args:
  389. raise TypeError("descriptor '__init__' of 'Counter' object "
  390. "needs an argument")
  391. self = args[0]
  392. args = args[1:]
  393. if len(args) > 1:
  394. raise TypeError('expected at most 1 arguments, got %d' % len(args))
  395. super(Counter, self).__init__()
  396. self.update(*args, **kwds)
  397. def __missing__(self, key):
  398. 'The count of elements not in the Counter is zero.'
  399. # Needed so that self[missing_item] does not raise KeyError
  400. return 0
  401. def most_common(self, n=None):
  402. '''List the n most common elements and their counts from the most
  403. common to the least. If n is None, then list all element counts.
  404. >>> Counter('abcdeabcdabcaba').most_common(3)
  405. [('a', 5), ('b', 4), ('c', 3)]
  406. '''
  407. # Emulate Bag.sortedByCount from Smalltalk
  408. if n is None:
  409. return sorted(self.iteritems(), key=_itemgetter(1), reverse=True)
  410. return _heapq.nlargest(n, self.iteritems(), key=_itemgetter(1))
  411. def elements(self):
  412. '''Iterator over elements repeating each as many times as its count.
  413. >>> c = Counter('ABCABC')
  414. >>> sorted(c.elements())
  415. ['A', 'A', 'B', 'B', 'C', 'C']
  416. # Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1
  417. >>> prime_factors = Counter({2: 2, 3: 3, 17: 1})
  418. >>> product = 1
  419. >>> for factor in prime_factors.elements(): # loop over factors
  420. ... product *= factor # and multiply them
  421. >>> product
  422. 1836
  423. Note, if an element's count has been set to zero or is a negative
  424. number, elements() will ignore it.
  425. '''
  426. # Emulate Bag.do from Smalltalk and Multiset.begin from C++.
  427. return _chain.from_iterable(_starmap(_repeat, self.iteritems()))
  428. # Override dict methods where necessary
  429. @classmethod
  430. def fromkeys(cls, iterable, v=None):
  431. # There is no equivalent method for counters because setting v=1
  432. # means that no element can have a count greater than one.
  433. raise NotImplementedError(
  434. 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.')
  435. def update(*args, **kwds):
  436. '''Like dict.update() but add counts instead of replacing them.
  437. Source can be an iterable, a dictionary, or another Counter instance.
  438. >>> c = Counter('which')
  439. >>> c.update('witch') # add elements from another iterable
  440. >>> d = Counter('watch')
  441. >>> c.update(d) # add elements from another counter
  442. >>> c['h'] # four 'h' in which, witch, and watch
  443. 4
  444. '''
  445. # The regular dict.update() operation makes no sense here because the
  446. # replace behavior results in the some of original untouched counts
  447. # being mixed-in with all of the other counts for a mismash that
  448. # doesn't have a straight-forward interpretation in most counting
  449. # contexts. Instead, we implement straight-addition. Both the inputs
  450. # and outputs are allowed to contain zero and negative counts.
  451. if not args:
  452. raise TypeError("descriptor 'update' of 'Counter' object "
  453. "needs an argument")
  454. self = args[0]
  455. args = args[1:]
  456. if len(args) > 1:
  457. raise TypeError('expected at most 1 arguments, got %d' % len(args))
  458. iterable = args[0] if args else None
  459. if iterable is not None:
  460. if isinstance(iterable, Mapping):
  461. if self:
  462. self_get = self.get
  463. for elem, count in iterable.iteritems():
  464. self[elem] = self_get(elem, 0) + count
  465. else:
  466. super(Counter, self).update(iterable) # fast path when counter is empty
  467. else:
  468. self_get = self.get
  469. for elem in iterable:
  470. self[elem] = self_get(elem, 0) + 1
  471. if kwds:
  472. self.update(kwds)
  473. def subtract(*args, **kwds):
  474. '''Like dict.update() but subtracts counts instead of replacing them.
  475. Counts can be reduced below zero. Both the inputs and outputs are
  476. allowed to contain zero and negative counts.
  477. Source can be an iterable, a dictionary, or another Counter instance.
  478. >>> c = Counter('which')
  479. >>> c.subtract('witch') # subtract elements from another iterable
  480. >>> c.subtract(Counter('watch')) # subtract elements from another counter
  481. >>> c['h'] # 2 in which, minus 1 in witch, minus 1 in watch
  482. 0
  483. >>> c['w'] # 1 in which, minus 1 in witch, minus 1 in watch
  484. -1
  485. '''
  486. if not args:
  487. raise TypeError("descriptor 'subtract' of 'Counter' object "
  488. "needs an argument")
  489. self = args[0]
  490. args = args[1:]
  491. if len(args) > 1:
  492. raise TypeError('expected at most 1 arguments, got %d' % len(args))
  493. iterable = args[0] if args else None
  494. if iterable is not None:
  495. self_get = self.get
  496. if isinstance(iterable, Mapping):
  497. for elem, count in iterable.items():
  498. self[elem] = self_get(elem, 0) - count
  499. else:
  500. for elem in iterable:
  501. self[elem] = self_get(elem, 0) - 1
  502. if kwds:
  503. self.subtract(kwds)
  504. def copy(self):
  505. 'Return a shallow copy.'
  506. return self.__class__(self)
  507. def __reduce__(self):
  508. return self.__class__, (dict(self),)
  509. def __delitem__(self, elem):
  510. 'Like dict.__delitem__() but does not raise KeyError for missing values.'
  511. if elem in self:
  512. super(Counter, self).__delitem__(elem)
  513. def __repr__(self):
  514. if not self:
  515. return '%s()' % self.__class__.__name__
  516. items = ', '.join(map('%r: %r'.__mod__, self.most_common()))
  517. return '%s({%s})' % (self.__class__.__name__, items)
  518. # Multiset-style mathematical operations discussed in:
  519. # Knuth TAOCP Volume II section 4.6.3 exercise 19
  520. # and at http://en.wikipedia.org/wiki/Multiset
  521. #
  522. # Outputs guaranteed to only include positive counts.
  523. #
  524. # To strip negative and zero counts, add-in an empty counter:
  525. # c += Counter()
  526. def __add__(self, other):
  527. '''Add counts from two counters.
  528. >>> Counter('abbb') + Counter('bcc')
  529. Counter({'b': 4, 'c': 2, 'a': 1})
  530. '''
  531. if not isinstance(other, Counter):
  532. return NotImplemented
  533. result = Counter()
  534. for elem, count in self.items():
  535. newcount = count + other[elem]
  536. if newcount > 0:
  537. result[elem] = newcount
  538. for elem, count in other.items():
  539. if elem not in self and count > 0:
  540. result[elem] = count
  541. return result
  542. def __sub__(self, other):
  543. ''' Subtract count, but keep only results with positive counts.
  544. >>> Counter('abbbc') - Counter('bccd')
  545. Counter({'b': 2, 'a': 1})
  546. '''
  547. if not isinstance(other, Counter):
  548. return NotImplemented
  549. result = Counter()
  550. for elem, count in self.items():
  551. newcount = count - other[elem]
  552. if newcount > 0:
  553. result[elem] = newcount
  554. for elem, count in other.items():
  555. if elem not in self and count < 0:
  556. result[elem] = 0 - count
  557. return result
  558. def __or__(self, other):
  559. '''Union is the maximum of value in either of the input counters.
  560. >>> Counter('abbb') | Counter('bcc')
  561. Counter({'b': 3, 'c': 2, 'a': 1})
  562. '''
  563. if not isinstance(other, Counter):
  564. return NotImplemented
  565. result = Counter()
  566. for elem, count in self.items():
  567. other_count = other[elem]
  568. newcount = other_count if count < other_count else count
  569. if newcount > 0:
  570. result[elem] = newcount
  571. for elem, count in other.items():
  572. if elem not in self and count > 0:
  573. result[elem] = count
  574. return result
  575. def __and__(self, other):
  576. ''' Intersection is the minimum of corresponding counts.
  577. >>> Counter('abbb') & Counter('bcc')
  578. Counter({'b': 1})
  579. '''
  580. if not isinstance(other, Counter):
  581. return NotImplemented
  582. result = Counter()
  583. for elem, count in self.items():
  584. other_count = other[elem]
  585. newcount = count if count < other_count else other_count
  586. if newcount > 0:
  587. result[elem] = newcount
  588. return result
  589. if __name__ == '__main__':
  590. # verify that instances can be pickled
  591. from cPickle import loads, dumps
  592. Point = namedtuple('Point', 'x, y', True)
  593. p = Point(x=10, y=20)
  594. assert p == loads(dumps(p))
  595. # test and demonstrate ability to override methods
  596. class Point(namedtuple('Point', 'x y')):
  597. __slots__ = ()
  598. @property
  599. def hypot(self):
  600. return (self.x ** 2 + self.y ** 2) ** 0.5
  601. def __str__(self):
  602. return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
  603. for p in Point(3, 4), Point(14, 5/7.):
  604. print p
  605. class Point(namedtuple('Point', 'x y')):
  606. 'Point class with optimized _make() and _replace() without error-checking'
  607. __slots__ = ()
  608. _make = classmethod(tuple.__new__)
  609. def _replace(self, _map=map, **kwds):
  610. return self._make(_map(kwds.get, ('x', 'y'), self))
  611. print Point(11, 22)._replace(x=100)
  612. Point3D = namedtuple('Point3D', Point._fields + ('z',))
  613. print Point3D.__doc__
  614. import doctest
  615. TestResults = namedtuple('TestResults', 'failed attempted')
  616. print TestResults(*doctest.testmod())