Skip to content

Commit

Permalink
feat: union(other)
Browse files Browse the repository at this point in the history
  • Loading branch information
eturino committed Jul 31, 2021
1 parent f30d743 commit 27e992e
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 2 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ TBD
## TODO

- remove
- union

## Limitations

Expand Down Expand Up @@ -51,7 +50,11 @@ Returns a new KeySet that represents the inverse Set of this one.

### `intersect(other)`

Returns a new KeySet with the intersection (A ∩ B) of both Sets.
Returns a new KeySet with the intersection (A ∩ B) of both Sets: a set that contains the elements included in both sets.

### `union(other)`

Returns a new KeySet with the union (A ∩ B) of both Sets: a set that contains the elements in any of the sets.

### `includes(element)`

Expand Down
46 changes: 46 additions & 0 deletions key_set/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ def clone(self) -> KeySet:
"""Returns a new KeySet that represents the same Set of this one."""
pass

@abstractmethod
def intersect(self, other: KeySet) -> KeySet:
"""Returns a new KeySet that represents the intersection (A ∩ B)."""
pass

@abstractmethod
def union(self, other: KeySet) -> KeySet:
"""Returns a new KeySet that contains the elements of both (A U B)."""
pass


class KeySetAll(KeySet):
"""Represents the ALL sets: 𝕌 (the entirety of possible keys)."""
Expand Down Expand Up @@ -99,6 +109,10 @@ def intersect(self, other: KeySet) -> KeySet:
"""Returns a new KeySet that represents the intersection (A ∩ B)."""
return other.clone()

def union(self, _other: KeySet) -> KeySet:
"""Returns a new KeySet that contains the elements of both (A U B)."""
return self.clone()


class KeySetNone(KeySet):
"""Represents the NONE sets: ø (empty set)."""
Expand Down Expand Up @@ -139,6 +153,10 @@ def intersect(self, _other: KeySet) -> KeySetNone:
"""Returns a new KeySet that represents the intersection (A ∩ B)."""
return self.clone()

def union(self, other: KeySet) -> KeySet:
"""Returns a new KeySet that contains the elements of both (A U B)."""
return other.clone()


class KeySetSome(KeySet):
"""Represents the SOME sets: a concrete set (`A ⊂ 𝕌`)."""
Expand Down Expand Up @@ -196,6 +214,20 @@ def intersect(self, other: KeySet) -> KeySet:
return build_some_or_none(elems)
return NotImplemented

def union(self, other: KeySet) -> KeySet:
"""Returns a new KeySet that contains the elements of both (A U B)."""
if other.represents_all():
return other.clone()
if other.represents_none():
return self.clone()
if other.represents_some():
elems = self._elements.union(other.elements())
return build_some_or_none(elems)
if other.represents_all_except_some():
elems = other.elements().difference(self._elements)
return build_all_except_some_or_all(elems)
return NotImplemented


class KeySetAllExceptSome(KeySet):
"""Represents the ALL_EXCEPT_SOME sets: the complementary of a concrete set.
Expand Down Expand Up @@ -256,6 +288,20 @@ def intersect(self, other: KeySet) -> KeySet:
return build_all_except_some_or_all(elems)
return NotImplemented

def union(self, other: KeySet) -> KeySet:
"""Returns a new KeySet that contains the elements of both (A U B)."""
if other.represents_all():
return other.clone()
if other.represents_none():
return self.clone()
if other.represents_some():
elems = self._elements.difference(other.elements())
return build_all_except_some_or_all(elems)
if other.represents_all_except_some():
elems = other.elements().intersection(self._elements)
return build_all_except_some_or_all(elems)
return NotImplemented


TS = Union[KeySetSome, KeySetNone]
TAES = Union[KeySetAllExceptSome, KeySetAll]
Expand Down
24 changes: 24 additions & 0 deletions tests/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,27 @@ def test_intersect_all_except_some(self) -> None:
def test_includes(self) -> None:
ks = KeySetAll()
assert ks.includes('a')

def test_union_all(self) -> None:
ks = KeySetAll()
other = KeySetAll()
actual = ks.union(other)
assert actual.represents_all()

def test_union_none(self) -> None:
ks = KeySetAll()
other = KeySetNone()
actual = ks.union(other)
assert actual.represents_all()

def test_union_some(self) -> None:
ks = KeySetAll()
other = KeySetSome({'a', 'b'})
actual = ks.union(other)
assert actual.represents_all()

def test_union_all_except_some(self) -> None:
ks = KeySetAll()
other = KeySetAllExceptSome({'a', 'b'})
actual = ks.union(other)
assert actual.represents_all()
82 changes: 82 additions & 0 deletions tests/test_all_except_some.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,85 @@ def test_includes_included(self) -> None:
def test_includes_missing(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
assert ks.includes('c')

def test_union_all(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetAll()
actual = ks.union(other)
assert actual.represents_all()
assert actual == other
assert actual is not other

def test_union_none(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetNone()
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'a', 'b'}

def test_union_some_same_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetSome({'a', 'b'})
actual = ks.union(other)
assert actual.represents_all()

def test_union_some_subset_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetSome({'a'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'b'}

def test_union_some_superset_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetSome({'a', 'b', 'c'})
actual = ks.union(other)
assert actual.represents_all()

def test_union_some_with_some_common_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetSome({'a', 'c'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'b'}

def test_union_some_without_common_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetSome({'c', 'd'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'a', 'b'}

def test_union_all_except_some_same_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetAllExceptSome({'a', 'b'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'a', 'b'}

def test_union_all_except_some_subset_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetAllExceptSome({'a'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'a'}

def test_union_all_except_some_superset_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetAllExceptSome({'a', 'b', 'c'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'a', 'b'}

def test_union_all_except_some_with_some_common_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetAllExceptSome({'a', 'c'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'a'}

def test_union_all_except_some_without_common_keys(self) -> None:
ks = KeySetAllExceptSome({'a', 'b'})
other = KeySetAllExceptSome({'c', 'd'})
actual = ks.union(other)
assert actual.represents_all()
30 changes: 30 additions & 0 deletions tests/test_none.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,33 @@ def test_intersect_all_except_some(self) -> None:
def test_includes(self) -> None:
ks = KeySetNone()
assert not ks.includes('a')

def test_union_all(self) -> None:
ks = KeySetNone()
other = KeySetAll()
actual = ks.union(other)
assert actual.represents_all()

def test_union_none(self) -> None:
ks = KeySetNone()
other = KeySetNone()
actual = ks.union(other)
assert actual.represents_none()

def test_union_some(self) -> None:
ks = KeySetNone()
other = KeySetSome({'a', 'b'})
actual = ks.union(other)
assert actual.represents_some()
assert actual.elements() == {'a', 'b'}
assert actual == other
assert actual is not other

def test_union_all_except_some(self) -> None:
ks = KeySetNone()
other = KeySetAllExceptSome({'a', 'b'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'a', 'b'}
assert actual == other
assert actual is not other
81 changes: 81 additions & 0 deletions tests/test_some.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,84 @@ def test_includes_included(self) -> None:
def test_includes_missing(self) -> None:
ks = KeySetSome({'a', 'b'})
assert not ks.includes('c')

def test_union_all(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetAll()
actual = ks.union(other)
assert actual.represents_all()

def test_union_none(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetNone()
actual = ks.union(other)
assert actual.represents_some()
assert actual.elements() == {'a', 'b'}

def test_union_some_same_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetSome({'a', 'b'})
actual = ks.union(other)
assert actual.represents_some()
assert actual.elements() == {'a', 'b'}

def test_union_some_subset_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetSome({'a'})
actual = ks.union(other)
assert actual.represents_some()
assert actual.elements() == {'a', 'b'}

def test_union_some_superset_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetSome({'a', 'b', 'c'})
actual = ks.union(other)
assert actual.represents_some()
assert actual.elements() == {'a', 'b', 'c'}

def test_union_some_with_some_common_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetSome({'a', 'c'})
actual = ks.union(other)
assert actual.represents_some()
assert actual.elements() == {'a', 'b', 'c'}

def test_union_some_without_common_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetSome({'c', 'd'})
actual = ks.union(other)
assert actual.represents_some()
assert actual.elements() == {'a', 'b', 'c', 'd'}

def test_union_all_except_some_same_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetAllExceptSome({'a', 'b'})
actual = ks.union(other)
assert actual.represents_all()

def test_union_all_except_some_subset_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetAllExceptSome({'a'})
actual = ks.union(other)
assert actual.represents_all()

def test_union_all_except_some_superset_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetAllExceptSome({'a', 'b', 'c'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'c'}

def test_union_all_except_some_with_some_common_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetAllExceptSome({'a', 'c'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'c'}

def test_union_all_except_some_without_common_keys(self) -> None:
ks = KeySetSome({'a', 'b'})
other = KeySetAllExceptSome({'c', 'd'})
actual = ks.union(other)
assert actual.represents_all_except_some()
assert actual.elements() == {'c', 'd'}

0 comments on commit 27e992e

Please sign in to comment.