1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
from __future__ import annotations
from collections.abc import Callable
from typing import Generic, Iterable, Self, TypeAlias, TypeVar
from ._iter import CruIterable
_T = TypeVar("_T")
class CruListEdit(CruIterable.Wrapper[_T]):
def done(self) -> CruList[_T]:
l: CruList[_T] = self.my_attr["list"]
l.reset(self)
return l
class CruList(list[_T]):
def reset(self, new_values: Iterable[_T]):
if self is new_values:
new_values = list(new_values)
self.clear()
self.extend(new_values)
return self
def as_iterable_wrapper(self) -> CruIterable.Wrapper[_T]:
return CruIterable.Wrapper(self)
def as_edit_iterable_wrapper(self) -> CruListEdit[_T]:
return CruListEdit(self, attr={"list": self})
@staticmethod
def make(maybe_list: Iterable[_T] | _T | None) -> CruList[_T]:
if maybe_list is None:
return CruList()
if isinstance(maybe_list, Iterable):
return CruList(maybe_list)
return CruList([maybe_list])
_K = TypeVar("_K")
_KeyGetter: TypeAlias = Callable[[_T], _K]
class CruUniqueKeyList(Generic[_T, _K]):
def __init__(
self,
key_getter: _KeyGetter[_T, _K],
*,
before_add: Callable[[_T], _T] | None = None,
):
super().__init__()
self._key_getter = key_getter
self._before_add = before_add
self._list: CruList[_T] = CruList()
@property
def key_getter(self) -> _KeyGetter[_T, _K]:
return self._key_getter
@property
def internal_list(self) -> CruList[_T]:
return self._list
def validate_self(self):
keys = self._list.transform(self._key_getter)
if len(keys) != len(set(keys)):
raise ValueError("Duplicate keys!")
# TODO: Continue here!
def get_or(self, key: K, fallback: Any = CRU_NOT_FOUND) -> _V | Any:
r = self._l.find_if(lambda i: k == self._key_getter(i))
return r if r is not CRU_NOT_FOUND else fallback
def get(self, k: K) -> _V:
v = self.get_or(k, CRU_NOT_FOUND)
if v is CRU_NOT_FOUND:
raise KeyError(f"Key not found!")
return v
def has_key(self, k: K) -> bool:
return self.get_or(k, CRU_NOT_FOUND) is not CRU_NOT_FOUND
def has_any_key(self, *k: K) -> bool:
return self._l.any(lambda i: self._key_getter(i) in k)
def try_remove(self, k: K) -> bool:
i = self._l.find_index_if(lambda v: k == self._key_getter(v))
if i is CRU_NOT_FOUND:
return False
self._l.remove_by_indices(i)
return True
def remove(self, k: K, allow_absense: bool = False) -> None:
if not self.try_remove(k) and not allow_absense:
raise KeyError(f"Key {k} not found!")
def add(self, v: _V, /, replace: bool = False) -> None:
if self.has_key(self._key_getter(v)):
if replace:
self.remove(self._key_getter(v))
else:
raise ValueError(f"Key {self._key_getter(v)} already exists!")
if self._before_add is not None:
v = self._before_add(v)
self._l.append(v)
def set(self, v: _V) -> None:
self.add(v, True)
def extend(self, l: Iterable[_V], /, replace: bool = False) -> None:
if not replace and self.has_any_key([self._key_getter(i) for i in l]):
raise ValueError("Keys already exists!")
if self._before_add is not None:
l = [self._before_add(i) for i in l]
keys = [self._key_getter(i) for i in l]
self._l.remove_all_if(lambda i: self._key_getter(i) in keys).extend(l)
def clear(self) -> None:
self._l.clear()
def __iter__(self):
return iter(self._l)
def __len__(self):
return len(self._l)
|