bpo-36057 Update docs and tests for ordering in collections.Counter [no behavior change] (#11962)
* Add tests for Counter order. No behavior change. * Update docs and tests * Fix doctest output and capitalization
This commit is contained in:
parent
86f093f71a
commit
407c734326
|
@ -268,6 +268,11 @@ For example::
|
|||
|
||||
.. versionadded:: 3.1
|
||||
|
||||
.. versionchanged:: 3.7 As a :class:`dict` subclass, :class:`Counter`
|
||||
Inherited the capability to remember insertion order. Math operations
|
||||
on *Counter* objects also preserve order. Results are ordered
|
||||
according to when an element is first encountered in the left operand
|
||||
and then by the order encountered in the right operand.
|
||||
|
||||
Counter objects support three methods beyond those available for all
|
||||
dictionaries:
|
||||
|
@ -275,8 +280,8 @@ For example::
|
|||
.. method:: elements()
|
||||
|
||||
Return an iterator over elements repeating each as many times as its
|
||||
count. Elements are returned in arbitrary order. If an element's count
|
||||
is less than one, :meth:`elements` will ignore it.
|
||||
count. Elements are returned in the order first encountered. If an
|
||||
element's count is less than one, :meth:`elements` will ignore it.
|
||||
|
||||
>>> c = Counter(a=4, b=2, c=0, d=-2)
|
||||
>>> sorted(c.elements())
|
||||
|
@ -287,10 +292,10 @@ For example::
|
|||
Return a list of the *n* most common elements and their counts from the
|
||||
most common to the least. If *n* is omitted or ``None``,
|
||||
:meth:`most_common` returns *all* elements in the counter.
|
||||
Elements with equal counts are ordered arbitrarily:
|
||||
Elements with equal counts are ordered in the order first encountered:
|
||||
|
||||
>>> Counter('abracadabra').most_common(3) # doctest: +SKIP
|
||||
[('a', 5), ('r', 2), ('b', 2)]
|
||||
>>> Counter('abracadabra').most_common(3)
|
||||
[('a', 5), ('b', 2), ('r', 2)]
|
||||
|
||||
.. method:: subtract([iterable-or-mapping])
|
||||
|
||||
|
|
|
@ -570,8 +570,8 @@ class Counter(dict):
|
|||
'''List the n most common elements and their counts from the most
|
||||
common to the least. If n is None, then list all element counts.
|
||||
|
||||
>>> Counter('abcdeabcdabcaba').most_common(3)
|
||||
[('a', 5), ('b', 4), ('c', 3)]
|
||||
>>> Counter('abracadabra').most_common(3)
|
||||
[('a', 5), ('b', 2), ('r', 2)]
|
||||
|
||||
'''
|
||||
# Emulate Bag.sortedByCount from Smalltalk
|
||||
|
|
|
@ -1881,6 +1881,63 @@ class TestCounter(unittest.TestCase):
|
|||
self.assertRaises(TypeError, Counter, (), ())
|
||||
self.assertRaises(TypeError, Counter.__init__)
|
||||
|
||||
def test_order_preservation(self):
|
||||
# Input order dictates items() order
|
||||
self.assertEqual(list(Counter('abracadabra').items()),
|
||||
[('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)])
|
||||
# letters with same count: ^----------^ ^---------^
|
||||
|
||||
# Verify retention of order even when all counts are equal
|
||||
self.assertEqual(list(Counter('xyzpdqqdpzyx').items()),
|
||||
[('x', 2), ('y', 2), ('z', 2), ('p', 2), ('d', 2), ('q', 2)])
|
||||
|
||||
# Input order dictates elements() order
|
||||
self.assertEqual(list(Counter('abracadabra simsalabim').elements()),
|
||||
['a', 'a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b','r',
|
||||
'r', 'c', 'd', ' ', 's', 's', 'i', 'i', 'm', 'm', 'l'])
|
||||
|
||||
# Math operations order first by the order encountered in the left
|
||||
# operand and then by the order encounted in the right operand.
|
||||
ps = 'aaabbcdddeefggghhijjjkkl'
|
||||
qs = 'abbcccdeefffhkkllllmmnno'
|
||||
order = {letter: i for i, letter in enumerate(dict.fromkeys(ps + qs))}
|
||||
def correctly_ordered(seq):
|
||||
'Return true if the letters occur in the expected order'
|
||||
positions = [order[letter] for letter in seq]
|
||||
return positions == sorted(positions)
|
||||
|
||||
p, q = Counter(ps), Counter(qs)
|
||||
self.assertTrue(correctly_ordered(+p))
|
||||
self.assertTrue(correctly_ordered(-p))
|
||||
self.assertTrue(correctly_ordered(p + q))
|
||||
self.assertTrue(correctly_ordered(p - q))
|
||||
self.assertTrue(correctly_ordered(p | q))
|
||||
self.assertTrue(correctly_ordered(p & q))
|
||||
|
||||
p, q = Counter(ps), Counter(qs)
|
||||
p += q
|
||||
self.assertTrue(correctly_ordered(p))
|
||||
|
||||
p, q = Counter(ps), Counter(qs)
|
||||
p -= q
|
||||
self.assertTrue(correctly_ordered(p))
|
||||
|
||||
p, q = Counter(ps), Counter(qs)
|
||||
p |= q
|
||||
self.assertTrue(correctly_ordered(p))
|
||||
|
||||
p, q = Counter(ps), Counter(qs)
|
||||
p &= q
|
||||
self.assertTrue(correctly_ordered(p))
|
||||
|
||||
p, q = Counter(ps), Counter(qs)
|
||||
p.update(q)
|
||||
self.assertTrue(correctly_ordered(p))
|
||||
|
||||
p, q = Counter(ps), Counter(qs)
|
||||
p.subtract(q)
|
||||
self.assertTrue(correctly_ordered(p))
|
||||
|
||||
def test_update(self):
|
||||
c = Counter()
|
||||
c.update(self=42)
|
||||
|
|
Loading…
Reference in New Issue