pyochain 0.5.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyochain/__init__.py +5 -0
- pyochain/_core/__init__.py +23 -0
- pyochain/_core/_format.py +34 -0
- pyochain/_core/_main.py +205 -0
- pyochain/_core/_protocols.py +38 -0
- pyochain/_dict/__init__.py +3 -0
- pyochain/_dict/_filters.py +268 -0
- pyochain/_dict/_groups.py +175 -0
- pyochain/_dict/_iter.py +135 -0
- pyochain/_dict/_joins.py +139 -0
- pyochain/_dict/_main.py +113 -0
- pyochain/_dict/_maps.py +142 -0
- pyochain/_dict/_nested.py +272 -0
- pyochain/_dict/_process.py +204 -0
- pyochain/_iter/__init__.py +3 -0
- pyochain/_iter/_aggregations.py +324 -0
- pyochain/_iter/_booleans.py +227 -0
- pyochain/_iter/_dicts.py +243 -0
- pyochain/_iter/_eager.py +233 -0
- pyochain/_iter/_filters.py +510 -0
- pyochain/_iter/_joins.py +404 -0
- pyochain/_iter/_lists.py +308 -0
- pyochain/_iter/_main.py +466 -0
- pyochain/_iter/_maps.py +360 -0
- pyochain/_iter/_partitions.py +145 -0
- pyochain/_iter/_process.py +366 -0
- pyochain/_iter/_rolling.py +241 -0
- pyochain/_iter/_tuples.py +326 -0
- pyochain/py.typed +0 -0
- pyochain-0.5.3.dist-info/METADATA +261 -0
- pyochain-0.5.3.dist-info/RECORD +32 -0
- pyochain-0.5.3.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Mapping
|
|
4
|
+
from functools import partial
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Concatenate, TypeIs
|
|
6
|
+
|
|
7
|
+
import cytoolz as cz
|
|
8
|
+
|
|
9
|
+
from .._core import MappingWrapper
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from ._main import Dict
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _drop_nones(
|
|
16
|
+
data: dict[Any, Any] | list[Any], remove_empty: bool = True
|
|
17
|
+
) -> dict[Any, Any] | list[Any] | None:
|
|
18
|
+
match data:
|
|
19
|
+
case dict():
|
|
20
|
+
pruned_dict: dict[Any, Any] = {}
|
|
21
|
+
for k, v in data.items():
|
|
22
|
+
pruned_v = _drop_nones(v, remove_empty)
|
|
23
|
+
|
|
24
|
+
is_empty = remove_empty and (pruned_v is None or pruned_v in ({}, []))
|
|
25
|
+
if not is_empty:
|
|
26
|
+
pruned_dict[k] = pruned_v
|
|
27
|
+
return pruned_dict if pruned_dict or not remove_empty else None
|
|
28
|
+
|
|
29
|
+
case list():
|
|
30
|
+
pruned_list = [_drop_nones(item, remove_empty) for item in data]
|
|
31
|
+
if remove_empty:
|
|
32
|
+
pruned_list = [
|
|
33
|
+
item
|
|
34
|
+
for item in pruned_list
|
|
35
|
+
if not (item is None or item in ({}, []))
|
|
36
|
+
]
|
|
37
|
+
return pruned_list if pruned_list or not remove_empty else None
|
|
38
|
+
|
|
39
|
+
case _:
|
|
40
|
+
if remove_empty and data is None:
|
|
41
|
+
return None
|
|
42
|
+
return data
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class NestedDict[K, V](MappingWrapper[K, V]):
|
|
46
|
+
def struct[**P, R, U: dict[Any, Any]](
|
|
47
|
+
self: NestedDict[K, U],
|
|
48
|
+
func: Callable[Concatenate[Dict[K, U], P], R],
|
|
49
|
+
*args: P.args,
|
|
50
|
+
**kwargs: P.kwargs,
|
|
51
|
+
) -> Dict[K, R]:
|
|
52
|
+
"""
|
|
53
|
+
Apply a function to each value after wrapping it in a Dict.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
func: Function to apply to each value after wrapping it in a Dict.
|
|
57
|
+
*args: Positional arguments to pass to the function.
|
|
58
|
+
**kwargs: Keyword arguments to pass to the function.
|
|
59
|
+
|
|
60
|
+
Syntactic sugar for `map_values(lambda data: func(pc.Dict(data), *args, **kwargs))`
|
|
61
|
+
```python
|
|
62
|
+
>>> import pyochain as pc
|
|
63
|
+
>>> data = {
|
|
64
|
+
... "person1": {"name": "Alice", "age": 30, "city": "New York"},
|
|
65
|
+
... "person2": {"name": "Bob", "age": 25, "city": "Los Angeles"},
|
|
66
|
+
... }
|
|
67
|
+
>>> pc.Dict(data).struct(lambda d: d.map_keys(str.upper).drop("AGE").unwrap())
|
|
68
|
+
... # doctest: +NORMALIZE_WHITESPACE
|
|
69
|
+
{'person1': {'CITY': 'New York', 'NAME': 'Alice'},
|
|
70
|
+
'person2': {'CITY': 'Los Angeles', 'NAME': 'Bob'}}
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
"""
|
|
74
|
+
from ._main import Dict
|
|
75
|
+
|
|
76
|
+
def _struct(data: Mapping[K, U]) -> dict[K, R]:
|
|
77
|
+
def _(v: dict[Any, Any]) -> R:
|
|
78
|
+
return func(Dict(v), *args, **kwargs)
|
|
79
|
+
|
|
80
|
+
return cz.dicttoolz.valmap(_, data)
|
|
81
|
+
|
|
82
|
+
return self._new(_struct)
|
|
83
|
+
|
|
84
|
+
def flatten(
|
|
85
|
+
self: NestedDict[str, Any], sep: str = ".", max_depth: int | None = None
|
|
86
|
+
) -> Dict[str, Any]:
|
|
87
|
+
"""
|
|
88
|
+
Flatten a nested dictionary, concatenating keys with the specified separator.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
sep: Separator to use when concatenating keys
|
|
92
|
+
max_depth: Maximum depth to flatten. If None, flattens completely.
|
|
93
|
+
```python
|
|
94
|
+
>>> import pyochain as pc
|
|
95
|
+
>>> data = {
|
|
96
|
+
... "config": {"params": {"retries": 3, "timeout": 30}, "mode": "fast"},
|
|
97
|
+
... "version": 1.0,
|
|
98
|
+
... }
|
|
99
|
+
>>> pc.Dict(data).flatten().unwrap()
|
|
100
|
+
{'config.params.retries': 3, 'config.params.timeout': 30, 'config.mode': 'fast', 'version': 1.0}
|
|
101
|
+
>>> pc.Dict(data).flatten(sep="_").unwrap()
|
|
102
|
+
{'config_params_retries': 3, 'config_params_timeout': 30, 'config_mode': 'fast', 'version': 1.0}
|
|
103
|
+
>>> pc.Dict(data).flatten(max_depth=1).unwrap()
|
|
104
|
+
{'config.params': {'retries': 3, 'timeout': 30}, 'config.mode': 'fast', 'version': 1.0}
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
def _flatten(
|
|
110
|
+
d: Mapping[Any, Any], parent_key: str = "", current_depth: int = 1
|
|
111
|
+
) -> dict[str, Any]:
|
|
112
|
+
def _can_recurse(v: object) -> TypeIs[Mapping[Any, Any]]:
|
|
113
|
+
return isinstance(v, Mapping) and (
|
|
114
|
+
max_depth is None or current_depth < max_depth + 1
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
items: list[tuple[str, Any]] = []
|
|
118
|
+
for k, v in d.items():
|
|
119
|
+
new_key = parent_key + sep + k if parent_key else k
|
|
120
|
+
if _can_recurse(v):
|
|
121
|
+
items.extend(_flatten(v, new_key, current_depth + 1).items())
|
|
122
|
+
else:
|
|
123
|
+
items.append((new_key, v))
|
|
124
|
+
return dict(items)
|
|
125
|
+
|
|
126
|
+
return self._new(_flatten)
|
|
127
|
+
|
|
128
|
+
def unpivot(
|
|
129
|
+
self: NestedDict[str, Mapping[str, Any]],
|
|
130
|
+
) -> Dict[str, dict[str, Any]]:
|
|
131
|
+
"""
|
|
132
|
+
Unpivot a nested dictionary by swapping rows and columns.
|
|
133
|
+
|
|
134
|
+
Example:
|
|
135
|
+
```python
|
|
136
|
+
>>> import pyochain as pc
|
|
137
|
+
>>> data = {
|
|
138
|
+
... "row1": {"col1": "A", "col2": "B"},
|
|
139
|
+
... "row2": {"col1": "C", "col2": "D"},
|
|
140
|
+
... }
|
|
141
|
+
>>> pc.Dict(data).unpivot()
|
|
142
|
+
... # doctest: +NORMALIZE_WHITESPACE
|
|
143
|
+
{'col1': {'row1': 'A', 'row2': 'C'}, 'col2': {'row1': 'B', 'row2': 'D'}}
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
def _unpivot(
|
|
147
|
+
data: Mapping[str, Mapping[str, Any]],
|
|
148
|
+
) -> dict[str, dict[str, Any]]:
|
|
149
|
+
out: dict[str, dict[str, Any]] = {}
|
|
150
|
+
for rkey, inner in data.items():
|
|
151
|
+
for ckey, val in inner.items():
|
|
152
|
+
out.setdefault(ckey, {})[rkey] = val
|
|
153
|
+
return out
|
|
154
|
+
|
|
155
|
+
return self._new(_unpivot)
|
|
156
|
+
|
|
157
|
+
def with_nested_key(self, *keys: K, value: V) -> Dict[K, V]:
|
|
158
|
+
"""
|
|
159
|
+
Set a nested key path and return a new Dict with new, potentially nested, key value pair.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
*keys: Sequence of keys representing the nested path.
|
|
163
|
+
value: Value to set at the specified nested path.
|
|
164
|
+
```python
|
|
165
|
+
>>> import pyochain as pc
|
|
166
|
+
>>> purchase = {
|
|
167
|
+
... "name": "Alice",
|
|
168
|
+
... "order": {"items": ["Apple", "Orange"], "costs": [0.50, 1.25]},
|
|
169
|
+
... "credit card": "5555-1234-1234-1234",
|
|
170
|
+
... }
|
|
171
|
+
>>> pc.Dict(purchase).with_nested_key(
|
|
172
|
+
... "order", "costs", value=[0.25, 1.00]
|
|
173
|
+
... ).unwrap()
|
|
174
|
+
{'name': 'Alice', 'order': {'items': ['Apple', 'Orange'], 'costs': [0.25, 1.0]}, 'credit card': '5555-1234-1234-1234'}
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
def _with_nested_key(data: dict[K, V]) -> dict[K, V]:
|
|
180
|
+
return cz.dicttoolz.assoc_in(data, keys, value=value)
|
|
181
|
+
|
|
182
|
+
return self._new(_with_nested_key)
|
|
183
|
+
|
|
184
|
+
def pluck[U: str | int](self: NestedDict[U, Any], *keys: str) -> Dict[U, Any]:
|
|
185
|
+
"""
|
|
186
|
+
Extract values from nested dictionaries using a sequence of keys.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
*keys: Sequence of keys to extract values from the nested dictionaries.
|
|
190
|
+
```python
|
|
191
|
+
>>> import pyochain as pc
|
|
192
|
+
>>> data = {
|
|
193
|
+
... "person1": {"name": "Alice", "age": 30},
|
|
194
|
+
... "person2": {"name": "Bob", "age": 25},
|
|
195
|
+
... }
|
|
196
|
+
>>> pc.Dict(data).pluck("name").unwrap()
|
|
197
|
+
{'person1': 'Alice', 'person2': 'Bob'}
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
getter = partial(cz.dicttoolz.get_in, keys)
|
|
203
|
+
|
|
204
|
+
def _pluck(data: Mapping[U, Any]) -> dict[U, Any]:
|
|
205
|
+
return cz.dicttoolz.valmap(getter, data)
|
|
206
|
+
|
|
207
|
+
return self._new(_pluck)
|
|
208
|
+
|
|
209
|
+
def get_in(self, *keys: K, default: Any = None) -> Any:
|
|
210
|
+
"""
|
|
211
|
+
Retrieve a value from a nested dictionary structure.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
*keys: Sequence of keys representing the nested path to retrieve the value.
|
|
215
|
+
default: Default value to return if the keys do not exist.
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
>>> import pyochain as pc
|
|
219
|
+
>>> data = {"a": {"b": {"c": 1}}}
|
|
220
|
+
>>> pc.Dict(data).get_in("a", "b", "c")
|
|
221
|
+
1
|
|
222
|
+
>>> pc.Dict(data).get_in("a", "x", default="Not Found")
|
|
223
|
+
'Not Found'
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
def _get_in(data: Mapping[K, V]) -> Any:
|
|
229
|
+
return cz.dicttoolz.get_in(keys, data, default)
|
|
230
|
+
|
|
231
|
+
return self.into(_get_in)
|
|
232
|
+
|
|
233
|
+
def drop_nones(self, remove_empty: bool = True) -> Dict[K, V]:
|
|
234
|
+
"""
|
|
235
|
+
Recursively drop None values from the dictionary.
|
|
236
|
+
|
|
237
|
+
Options to also remove empty dicts and lists.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
remove_empty: If True (default), removes `None`, `{}` and `[]`.
|
|
241
|
+
|
|
242
|
+
Example:
|
|
243
|
+
```python
|
|
244
|
+
>>> import pyochain as pc
|
|
245
|
+
>>> data = {
|
|
246
|
+
... "a": 1,
|
|
247
|
+
... "b": None,
|
|
248
|
+
... "c": {},
|
|
249
|
+
... "d": [],
|
|
250
|
+
... "e": {"f": None, "g": 2},
|
|
251
|
+
... "h": [1, None, {}],
|
|
252
|
+
... "i": 0,
|
|
253
|
+
... }
|
|
254
|
+
>>> p_data = pc.Dict(data)
|
|
255
|
+
>>>
|
|
256
|
+
>>> p_data.drop_nones().unwrap()
|
|
257
|
+
{'a': 1, 'e': {'g': 2}, 'h': [1], 'i': 0}
|
|
258
|
+
>>>
|
|
259
|
+
>>> p_data.drop_nones().unwrap()
|
|
260
|
+
{'a': 1, 'e': {'g': 2}, 'h': [1], 'i': 0}
|
|
261
|
+
>>>
|
|
262
|
+
>>> p_data.drop_nones(remove_empty=False).unwrap()
|
|
263
|
+
{'a': 1, 'b': None, 'c': {}, 'd': [], 'e': {'f': None, 'g': 2}, 'h': [1, None, {}], 'i': 0}
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
def _apply_drop_nones(data: dict[K, V]) -> dict[Any, Any]:
|
|
269
|
+
result = _drop_nones(data, remove_empty)
|
|
270
|
+
return result if isinstance(result, dict) else dict()
|
|
271
|
+
|
|
272
|
+
return self._new(_apply_drop_nones)
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Mapping
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Concatenate
|
|
5
|
+
|
|
6
|
+
import cytoolz as cz
|
|
7
|
+
|
|
8
|
+
from .._core import MappingWrapper, SupportsRichComparison
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ._main import Dict
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ProcessDict[K, V](MappingWrapper[K, V]):
|
|
15
|
+
def for_each[**P](
|
|
16
|
+
self,
|
|
17
|
+
func: Callable[Concatenate[K, V, P], Any],
|
|
18
|
+
*args: P.args,
|
|
19
|
+
**kwargs: P.kwargs,
|
|
20
|
+
) -> Dict[K, V]:
|
|
21
|
+
"""
|
|
22
|
+
Apply a function to each key-value pair in the dict for side effects.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
func: Function to apply to each key-value pair.
|
|
26
|
+
*args: Positional arguments to pass to the function.
|
|
27
|
+
**kwargs: Keyword arguments to pass to the function.
|
|
28
|
+
|
|
29
|
+
Returns the original Dict unchanged.
|
|
30
|
+
```python
|
|
31
|
+
>>> import pyochain as pc
|
|
32
|
+
>>> pc.Dict({"a": 1, "b": 2}).for_each(
|
|
33
|
+
... lambda k, v: print(f"Key: {k}, Value: {v}")
|
|
34
|
+
... ).unwrap()
|
|
35
|
+
Key: a, Value: 1
|
|
36
|
+
Key: b, Value: 2
|
|
37
|
+
{'a': 1, 'b': 2}
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def _for_each(data: dict[K, V]) -> dict[K, V]:
|
|
43
|
+
for k, v in data.items():
|
|
44
|
+
func(k, v, *args, **kwargs)
|
|
45
|
+
return data
|
|
46
|
+
|
|
47
|
+
return self._new(_for_each)
|
|
48
|
+
|
|
49
|
+
def update_in(
|
|
50
|
+
self, *keys: K, func: Callable[[V], V], default: V | None = None
|
|
51
|
+
) -> Dict[K, V]:
|
|
52
|
+
"""
|
|
53
|
+
Update value in a (potentially) nested dictionary.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
*keys: Sequence of keys representing the nested path to update.
|
|
57
|
+
func: Function to apply to the value at the specified path.
|
|
58
|
+
default: Default value to use if the path does not exist, by default None
|
|
59
|
+
|
|
60
|
+
Applies the func to the value at the path specified by keys, returning a new Dict with the updated value.
|
|
61
|
+
|
|
62
|
+
If the path does not exist, it will be created with the default value (if provided) before applying func.
|
|
63
|
+
```python
|
|
64
|
+
>>> import pyochain as pc
|
|
65
|
+
>>> inc = lambda x: x + 1
|
|
66
|
+
>>> pc.Dict({"a": 0}).update_in("a", func=inc).unwrap()
|
|
67
|
+
{'a': 1}
|
|
68
|
+
>>> transaction = {
|
|
69
|
+
... "name": "Alice",
|
|
70
|
+
... "purchase": {"items": ["Apple", "Orange"], "costs": [0.50, 1.25]},
|
|
71
|
+
... "credit card": "5555-1234-1234-1234",
|
|
72
|
+
... }
|
|
73
|
+
>>> pc.Dict(transaction).update_in("purchase", "costs", func=sum).unwrap()
|
|
74
|
+
{'name': 'Alice', 'purchase': {'items': ['Apple', 'Orange'], 'costs': 1.75}, 'credit card': '5555-1234-1234-1234'}
|
|
75
|
+
>>> # updating a value when k0 is not in d
|
|
76
|
+
>>> pc.Dict({}).update_in(1, 2, 3, func=str, default="bar").unwrap()
|
|
77
|
+
{1: {2: {3: 'bar'}}}
|
|
78
|
+
>>> pc.Dict({1: "foo"}).update_in(2, 3, 4, func=inc, default=0).unwrap()
|
|
79
|
+
{1: 'foo', 2: {3: {4: 1}}}
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
def _update_in(data: dict[K, V]) -> dict[K, V]:
|
|
85
|
+
return cz.dicttoolz.update_in(data, keys, func, default=default)
|
|
86
|
+
|
|
87
|
+
return self._new(_update_in)
|
|
88
|
+
|
|
89
|
+
def with_key(self, key: K, value: V) -> Dict[K, V]:
|
|
90
|
+
"""
|
|
91
|
+
Return a new Dict with key set to value.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
key: Key to set in the dictionary.
|
|
95
|
+
value: Value to associate with the specified key.
|
|
96
|
+
|
|
97
|
+
Does not modify the initial dictionary.
|
|
98
|
+
```python
|
|
99
|
+
>>> import pyochain as pc
|
|
100
|
+
>>> pc.Dict({"x": 1}).with_key("x", 2).unwrap()
|
|
101
|
+
{'x': 2}
|
|
102
|
+
>>> pc.Dict({"x": 1}).with_key("y", 3).unwrap()
|
|
103
|
+
{'x': 1, 'y': 3}
|
|
104
|
+
>>> pc.Dict({}).with_key("x", 1).unwrap()
|
|
105
|
+
{'x': 1}
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def _with_key(data: dict[K, V]) -> dict[K, V]:
|
|
111
|
+
return cz.dicttoolz.assoc(data, key, value)
|
|
112
|
+
|
|
113
|
+
return self._new(_with_key)
|
|
114
|
+
|
|
115
|
+
def drop(self, *keys: K) -> Dict[K, V]:
|
|
116
|
+
"""
|
|
117
|
+
Return a new Dict with given keys removed.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
*keys: Sequence of keys to remove from the dictionary.
|
|
121
|
+
|
|
122
|
+
New dict has d[key] deleted for each supplied key.
|
|
123
|
+
```python
|
|
124
|
+
>>> import pyochain as pc
|
|
125
|
+
>>> pc.Dict({"x": 1, "y": 2}).drop("y").unwrap()
|
|
126
|
+
{'x': 1}
|
|
127
|
+
>>> pc.Dict({"x": 1, "y": 2}).drop("y", "x").unwrap()
|
|
128
|
+
{}
|
|
129
|
+
>>> pc.Dict({"x": 1}).drop("y").unwrap() # Ignores missing keys
|
|
130
|
+
{'x': 1}
|
|
131
|
+
>>> pc.Dict({1: 2, 3: 4}).drop(1).unwrap()
|
|
132
|
+
{3: 4}
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
def _drop(data: dict[K, V]) -> dict[K, V]:
|
|
138
|
+
return cz.dicttoolz.dissoc(data, *keys)
|
|
139
|
+
|
|
140
|
+
return self._new(_drop)
|
|
141
|
+
|
|
142
|
+
def rename(self, mapping: Mapping[K, K]) -> Dict[K, V]:
|
|
143
|
+
"""
|
|
144
|
+
Return a new Dict with keys renamed according to the mapping.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
mapping: A dictionary mapping old keys to new keys.
|
|
148
|
+
|
|
149
|
+
Keys not in the mapping are kept as is.
|
|
150
|
+
```python
|
|
151
|
+
>>> import pyochain as pc
|
|
152
|
+
>>> d = {"a": 1, "b": 2, "c": 3}
|
|
153
|
+
>>> mapping = {"b": "beta", "c": "gamma"}
|
|
154
|
+
>>> pc.Dict(d).rename(mapping).unwrap()
|
|
155
|
+
{'a': 1, 'beta': 2, 'gamma': 3}
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
def _rename(data: dict[K, V]) -> dict[K, V]:
|
|
161
|
+
return {mapping.get(k, k): v for k, v in data.items()}
|
|
162
|
+
|
|
163
|
+
return self._new(_rename)
|
|
164
|
+
|
|
165
|
+
def sort(self, reverse: bool = False) -> Dict[K, V]:
|
|
166
|
+
"""
|
|
167
|
+
Sort the dictionary by its keys and return a new Dict.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
reverse: Whether to sort in descending order. Defaults to False.
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
>>> import pyochain as pc
|
|
174
|
+
>>> pc.Dict({"b": 2, "a": 1}).sort().unwrap()
|
|
175
|
+
{'a': 1, 'b': 2}
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
def _sort(data: dict[K, V]) -> dict[K, V]:
|
|
181
|
+
return dict(sorted(data.items(), reverse=reverse))
|
|
182
|
+
|
|
183
|
+
return self._new(_sort)
|
|
184
|
+
|
|
185
|
+
def sort_values[U: SupportsRichComparison[Any]](
|
|
186
|
+
self: ProcessDict[K, U], reverse: bool = False
|
|
187
|
+
) -> Dict[K, U]:
|
|
188
|
+
"""
|
|
189
|
+
Sort the dictionary by its values and return a new Dict.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
reverse: Whether to sort in descending order. Defaults to False.
|
|
193
|
+
```python
|
|
194
|
+
>>> import pyochain as pc
|
|
195
|
+
>>> pc.Dict({"a": 2, "b": 1}).sort_values().unwrap()
|
|
196
|
+
{'b': 1, 'a': 2}
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
def _sort_values(data: dict[K, U]) -> dict[K, U]:
|
|
202
|
+
return dict(sorted(data.items(), key=lambda item: item[1], reverse=reverse))
|
|
203
|
+
|
|
204
|
+
return self._new(_sort_values)
|