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