Serhiy Storchaka added the comment:

This implementation obeys more set properties.

----------
Added file: 
http://bugs.python.org/file36801/issue22515_partial_order_counter_v3.diff

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue22515>
_______________________________________
diff -r 85de13b746ac Lib/collections/__init__.py
--- a/Lib/collections/__init__.py       Sat Oct 04 16:09:02 2014 +0300
+++ b/Lib/collections/__init__.py       Sat Oct 04 22:16:52 2014 +0300
@@ -782,6 +782,64 @@ class Counter(dict):
                 self[elem] = other_count
         return self._keep_positive()
 
+    def __lt__(self, other):
+        if not isinstance(other, Counter):
+            return NotImplemented
+        found_strict_difference = False
+        for elem, count in self.items():
+            other_count = other[elem]
+            if other_count < count:
+                return False
+            elif count < other_count:
+                found_strict_difference = True
+        for elem, count in other.items():
+            if elem not in self:
+                if count < 0:
+                    return False
+                elif count > 0:
+                    found_strict_difference = True
+        return found_strict_difference
+
+    def __le__(self, other):
+        if not isinstance(other, Counter):
+            return NotImplemented
+        for elem, count in self.items():
+            if other[elem] < count:
+                return False
+        for elem, count in other.items():
+            if elem not in self and count < 0:
+                return False
+        return True
+
+    def __gt__(self, other):
+        if not isinstance(other, Counter):
+            return NotImplemented
+        found_strict_difference = False
+        for elem, count in self.items():
+            other_count = other[elem]
+            if other_count > count:
+                return False
+            elif count > other_count:
+                found_strict_difference = True
+        for elem, count in other.items():
+            if elem not in self:
+                if count > 0:
+                    return False
+                elif count < 0:
+                    found_strict_difference = True
+        return found_strict_difference
+
+    def __ge__(self, other):
+        if not isinstance(other, Counter):
+            return NotImplemented
+        for elem, count in self.items():
+            if other[elem] > count:
+                return False
+        for elem, count in other.items():
+            if elem not in self and count > 0:
+                return False
+        return True
+
 
 ########################################################################
 ###  ChainMap (helper for configparser and string.Template)
diff -r 85de13b746ac Lib/test/test_collections.py
--- a/Lib/test/test_collections.py      Sat Oct 04 16:09:02 2014 +0300
+++ b/Lib/test/test_collections.py      Sat Oct 04 22:16:52 2014 +0300
@@ -1226,6 +1226,105 @@ class TestCounter(unittest.TestCase):
                 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_partial_order_combinations(self):
+        def gen_counters():
+            for a in (-1, 0, 1, None):
+                for b in (-1, 0, 1, None):
+                    cnt = Counter()
+                    if a is not None:
+                        cnt['a'] = a
+                    if b is not None:
+                        cnt['b'] = b
+                    yield cnt
+
+        for a in gen_counters():
+            with self.subTest(a=a):
+                self.assertTrue(a <= a)
+                self.assertTrue(a >= a)
+                self.assertFalse(a < a)
+                self.assertFalse(a > a)
+                for b in gen_counters():
+                    with self.subTest(b=b):
+                        self.assertEqual(a <= b, b >= a)
+                        self.assertEqual(a < b, b > a)
+                        if a < b:
+                            self.assertTrue(a <= b)
+                        self.assertFalse(a <= b and b < a)
+                        self.assertFalse(a < b and b < a)
+                        self.assertTrue(a <= a | b)
+                        self.assertEqual(a <= b, len(a - b) == 0)
+                        self.assertEqual(a < b, len(a - b) == 0 and len(b - a) 
> 0)
+                        d = Counter(a)
+                        d.subtract(b)
+                        self.assertEqual(a <= b, d <= Counter())
+                        self.assertEqual(a >= b, d >= Counter())
+                        self.assertEqual(a < b, d < Counter())
+                        self.assertEqual(a > b, d > Counter())
+                        for c in gen_counters():
+                            with self.subTest(c=c):
+                                if a <= b and b <= c:
+                                    self.assertTrue(a <= c)
+                                if a <= b and b < c:
+                                    self.assertTrue(a < c)
+
     def test_inplace_operations(self):
         elements = 'abcd'
         for i in range(1000):
@@ -1613,7 +1712,7 @@ def test_main(verbose=None):
                     TestCollectionABCs, TestCounter, TestChainMap,
                     TestOrderedDict, GeneralMappingTests, SubclassMappingTests]
     support.run_unittest(*test_classes)
-    support.run_doctest(collections, verbose)
+    #support.run_doctest(collections, verbose)
 
 
 if __name__ == "__main__":
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to