Created
August 23, 2021 07:48
-
-
Save spumer/7b7e350db279f5a3cef90a4cfde2f41f to your computer and use it in GitHub Desktop.
AnyDict, UnorderedList
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import collections | |
from collections import UserDict | |
from collections import UserList | |
def maybe_hdict(value): | |
if isinstance(value, dict) and not isinstance(value, HDict): | |
return HDict(value) | |
return value | |
class HDict(UserDict): | |
def __hash__(self): | |
return hash(frozenset((k, maybe_hdict(v)) for k, v in self.items())) | |
# inherit from HDict to workaround dict comparision optimization: | |
# __eq__ not called if .keys() differ, but calls for sub-types | |
class AnyDict(HDict): | |
""" | |
>>> # Если ключа нет, он равен ANY | |
>>> any_dict = AnyDict({'key': 1}) | |
>>> extra_key_dict = {'key': 1, 'new_key': 2} | |
>>> any_dict == extra_key_dict | |
True | |
>>> # Если ключи совпадают: то они проверяются | |
>>> diff_value_dict = {'key': 2} | |
>>> any_dict == diff_value_dict | |
False | |
""" | |
def __eq__(self, other): | |
if not isinstance(other, collections.Mapping): | |
return False | |
for key, value in self.items(): | |
if key not in other: | |
return False | |
if other[key] != value: | |
return False | |
return True | |
class UnorderedList(UserList): | |
""" | |
>>> l1 = UnorderedList([1, 2, 3]) | |
>>> l2 = UnorderedList([3, 2, 1]) | |
>>> l1 == l2 | |
True | |
>>> l1 = UnorderedList([{'id': 1}, {'id': 2}]) | |
>>> l2 = UnorderedList([{'id': 2}, {'id': 1}]) | |
>>> l1 == l2 | |
True | |
""" | |
def __init__(self, initlist): | |
copy = [maybe_hdict(item) for item in initlist] | |
super().__init__(copy) | |
def __eq__(self, other): | |
if not isinstance(other, UnorderedList): | |
other = UnorderedList(other) | |
return compare(self, other) | |
def compare(s, t): | |
"""Compare with O(n * n) complexity | |
but AnyDict __eq__ logic works correctly | |
""" | |
t = list(t) | |
for elem in s: | |
if elem in t: | |
t.remove(elem) | |
else: | |
return False | |
return not t |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment