diff --git a/CHANGELOG.md b/CHANGELOG.md index 082feff71a1bccb1ca7aa4e1a346fb77594774ae..c87dc97a4bed599ebce4bfe12eaf100989ca17f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,4 +5,5 @@ * fixed a bug in DictionaryEQAble * fixed a bug in ListDeleter * minor breaking change: changed semantics of ListDeleter -* added `CPManager` \ No newline at end of file +* added `CPManager` +* added `SetZip` \ No newline at end of file diff --git a/docs/coding/structures.rst b/docs/coding/structures.rst index 611a2d7c6ae8388c42cc04f0ce72d89535da850d..0cf7a60e782828c7c7ae9427d1cab46e9f9af031 100644 --- a/docs/coding/structures.rst +++ b/docs/coding/structures.rst @@ -17,6 +17,13 @@ You can also use the following singleton. :members: +SetZip +------ + +.. autoclass:: satella.coding.structures.SetZip + :members: + + PushIterable ------------ diff --git a/satella/__init__.py b/satella/__init__.py index 1e2c5e419af0411134f297c9103b8bc4ac684a9e..6d2db50c097c278d885331e65be7b51a2178f18b 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.19.0rc3' +__version__ = '2.19.0' diff --git a/satella/coding/structures/__init__.py b/satella/coding/structures/__init__.py index 097432461496707e8137b4bef36a022b83bc671a..9677096d43acfc65c9268f8c30b5047c67c8f1d3 100644 --- a/satella/coding/structures/__init__.py +++ b/satella/coding/structures/__init__.py @@ -18,11 +18,12 @@ from .typednamedtuple import typednamedtuple from .lru import LRU from .syncable_droppable import DBStorage, SyncableDroppable from .tuples import Vector +from .zip_dict import SetZip from .push_iterable import PushIterable __all__ = [ 'PushIterable', - 'Vector', + 'Vector', 'SetZip', 'DBStorage', 'SyncableDroppable', 'LRU', 'LRUCacheDict', diff --git a/satella/coding/structures/zip_dict.py b/satella/coding/structures/zip_dict.py new file mode 100644 index 0000000000000000000000000000000000000000..0459607c19d452c9d60b885a98501fd05ae66bf8 --- /dev/null +++ b/satella/coding/structures/zip_dict.py @@ -0,0 +1,30 @@ +class SetZip: + """ + An object which zips a bunch of sets together. + + Ie. checks for inclusion by checking each set. + + Also supports len and iteration protocol. + + You can also add extra sets: + + >>> c = SetZip() + >>> c += set([1, 2, 3]) + + Provided arguments must implement contains, length and iter. + """ + def __iadd__(self, other: set): + self.args.append(other) + + def __init__(self, *args: set): + self.args = list(args) + + def __contains__(self, item) -> bool: + return any(item in arg for arg in self.args) + + def __len__(self) -> int: + return sum(len(arg) for arg in self.args) + + def __iter__(self): + for arg in self.args: + yield from arg diff --git a/tests/test_coding/test_structures.py b/tests/test_coding/test_structures.py index 720fb5e85bedc1001c4b16eb6ce4f95a5cb59cbb..9acf9550ec0c588a56d2356e0a388c3e206c048e 100644 --- a/tests/test_coding/test_structures.py +++ b/tests/test_coding/test_structures.py @@ -15,11 +15,24 @@ from satella.coding.structures import TimeBasedHeap, Heap, typednamedtuple, \ CacheDict, StrEqHashableMixin, ComparableIntEnum, HashableIntEnum, ComparableAndHashableBy, \ ComparableAndHashableByInt, SparseMatrix, ExclusiveWritebackCache, Subqueue, \ CountingDict, ComparableEnum, LRU, LRUCacheDict, Vector, DefaultDict, PushIterable, \ - ComparableAndHashableByStr, NotEqualToAnything, NOT_EQUAL_TO_ANYTHING, DictionaryEQAble + ComparableAndHashableByStr, NotEqualToAnything, NOT_EQUAL_TO_ANYTHING, DictionaryEQAble, SetZip class TestStructures(unittest.TestCase): + def test_zip(self): + a = set([1,2, 3]) + b = set([3,4,5]) + c = SetZip(a, b) + self.assertIn(4, c) + self.assertNotIn(9, c) + self.assertEqual(len(c), 6) + self.assertEqual(set(c), set([1,2,3,4,5])) + + c += set([0]) + self.assertEqual(len(c), 7) + self.assertIn(0, c) + def test_dictionary_eqable(self): class Dupa(DictionaryEQAble): def __init__(self, a):