diff -r a486b673b57f Lib/collections/__init__.py --- a/Lib/collections/__init__.py Fri Oct 03 20:18:48 2014 -0400 +++ b/Lib/collections/__init__.py Sat Oct 04 12:26:06 2014 +0530 @@ -754,6 +754,63 @@ return self._keep_positive() + # add partial order + # counter1 is less than counter2 if no element of counter1 is greater + # than the corresponding element of counter2, and at least one matching + # element is smaller; missing elements count as zero + + def __lt__(self, other): + if not isinstance(other, Mapping): + return NotImplemented + found_strict_difference = False # Until challenged. + for element, count in self.items(): + other_count = other.get(element, 0) + if count > other_count: + return False + elif count < other_count: + found_strict_difference = True + if not found_strict_difference: + # equal to this point -- does other mapping have more keys? + if len(self) < len(other): + return True + return found_strict_difference + + def __le__(self, other): + if not isinstance(other, Mapping): + return NotImplemented + for element, count in self.items(): + other_count = other.get(element, 0) + if count > other_count: + return False + # equal to this point -- does other mapping have more keys? + return len(self) <= len(other) + + def __gt__(self, other): + if not isinstance(other, Mapping): + return NotImplemented + found_strict_difference = False # Until challenged. + for element, count in self.items(): + other_count = other.get(element, 0) + if count < other_count: + return False + elif count > other_count: + found_strict_difference = True + if not found_strict_difference: + # equal to this point -- does other mapping have fewer keys? + if len(self) > len(other): + return True + return found_strict_difference + + def __ge__(self, other): + if not isinstance(other, Mapping): + return NotImplemented + for element, count in self.items(): + other_count = other.get(element, 0) + if count < other_count: + return False + # equal to this point -- does other mapping have fewer keys? + return len(self) >= len(other) + ######################################################################## ### ChainMap (helper for configparser and string.Template) ######################################################################## diff -r a486b673b57f Lib/test/test_collections.py --- a/Lib/test/test_collections.py Fri Oct 03 20:18:48 2014 -0400 +++ b/Lib/test/test_collections.py Sat Oct 04 12:26:06 2014 +0530 @@ -19,6 +19,7 @@ from collections.abc import Mapping, MutableMapping, KeysView, ItemsView from collections.abc import Sequence, MutableSequence from collections.abc import ByteString +import decimal ################################################################################ @@ -1173,6 +1174,64 @@ set_result = setop(set(p.elements()), set(q.elements())) self.assertEqual(counter_result, dict.fromkeys(set_result, 1)) + def test_partial_order(self): + counter_0 = Counter() + counter_1 = Counter('c') + counter_2 = Counter('abc') + counter_3 = Counter('aabc') + counter_4 = Counter('abbc') + counter_5 = Counter('aabbcc') + + bad_d = {'a': 'a', 'b': 'b', 'c': 'c'} + not_a_mapping = object() + + biggest = ( + (counter_5, (counter_4, counter_3, counter_2, counter_1, counter_0)), + (counter_4, (counter_2, counter_1, counter_0)), + (counter_3, (counter_2, counter_1, counter_0)), + (counter_2, (counter_1, )), + (counter_1, (counter_0, )), + ) + smallest = ( + (counter_0, (counter_1, counter_2, counter_3, counter_4, counter_5)), + (counter_1, (counter_2, counter_3, counter_4, counter_5)), + (counter_2, (counter_3, counter_4, counter_5)), + (counter_3, (counter_5, )), + (counter_4, (counter_5, )), + ) + for item, smaller_items in biggest: + for smaller_item in smaller_items: + self.assertFalse(item <= smaller_item) + self.assertFalse(item < smaller_item) + self.assertTrue(item >= smaller_item) + self.assertTrue(item > smaller_item) + self.assertTrue(item != smaller_item) + for item, bigger_items in smallest: + for bigger_item in bigger_items: + self.assertFalse(item >= bigger_item) + self.assertFalse(item > bigger_item) + self.assertTrue(item <= bigger_item) + self.assertTrue(item < bigger_item) + self.assertTrue(item != bigger_item) + for item in (counter_2, counter_3, counter_4, counter_5): + with self.assertRaises(TypeError): + item <= bad_d + with self.assertRaises(TypeError): + item < bad_d + with self.assertRaises(TypeError): + item >= bad_d + with self.assertRaises(TypeError): + item > bad_d + # other is not a mapping + with self.assertRaises(TypeError): + item <= not_a_mapping + with self.assertRaises(TypeError): + item < not_a_mapping + with self.assertRaises(TypeError): + item >= not_a_mapping + with self.assertRaises(TypeError): + item > not_a_mapping + def test_inplace_operations(self): elements = 'abcd' for i in range(1000):