lkj 0.1.39__py3-none-any.whl → 0.1.40__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.
lkj/dicts.py CHANGED
@@ -111,16 +111,10 @@ from typing import Mapping, Callable, TypeVar, Iterable, Tuple
111
111
  KT = TypeVar("KT") # Key type
112
112
  VT = TypeVar("VT") # Value type
113
113
 
114
+
114
115
  # Note: Could have all function parameters (recursive_condition, etc.) also take the
115
116
  # enumerated index of the mapping as an argument. That would give us even more
116
117
  # flexibility, but it might be overkill and make the interface more complex.
117
- from typing import Mapping, Callable, TypeVar, Iterable, Tuple
118
- from collections import defaultdict
119
-
120
- KT = TypeVar("KT") # Key type
121
- VT = TypeVar("VT") # Value type
122
-
123
-
124
118
  def merge_dicts(
125
119
  *mappings: Mapping[KT, VT],
126
120
  recursive_condition: Callable[[VT], bool] = lambda v: isinstance(v, Mapping),
@@ -221,3 +215,62 @@ def merge_dicts(
221
215
  merged[key] = value
222
216
 
223
217
  return merged
218
+
219
+
220
+ import operator
221
+ from typing import Callable, Dict, Any
222
+
223
+ Comparison = Any
224
+ Comparator = Callable[[dict, dict], Comparison]
225
+
226
+
227
+ def compare_dicts(
228
+ dict1,
229
+ dict2,
230
+ *,
231
+ field_comparators: Dict[KT, Comparator] = {},
232
+ default_comparator: Comparator = operator.eq,
233
+ aggregator: Callable[
234
+ [Dict[KT, Comparison]], Any
235
+ ] = lambda d: d, # lambda d: np.mean(list(d.values()))
236
+ ):
237
+ """
238
+ Compare two dictionaries field by field using specified comparators or a default comparator.
239
+
240
+ :param dict1: The first dictionary.
241
+ :param dict2: The second dictionary.
242
+ :param field_comparators: A dictionary where keys are field names and values are comparator functions.
243
+ :param default_comparator: A default comparator function to use if no specific comparator is provided for a field.
244
+ :param aggregator: A function to aggregate the comparison results into a final score.
245
+ :return: A final score based on the comparison results.
246
+
247
+ >>> dict1 = {"color": "brown", "animal": "dog"}
248
+ >>> dict2 = {"color": "brown", "animal": "cat"}
249
+ >>> dict3 = {"color": "brown", "animal": "bird"}
250
+ >>> field_comparators = {
251
+ ... "color": lambda x, y: 1 if x == y else 0,
252
+ ... "animal": lambda x, y: 1 if len(x) == len(y) else 0
253
+ ... }
254
+ >>> compare_dicts(dict1, dict2, field_comparators=field_comparators)
255
+ {'color': 1, 'animal': 1}
256
+ >>> compare_dicts(dict1, dict3, field_comparators=field_comparators)
257
+ {'color': 1, 'animal': 0}
258
+ >>> import functools, statistics
259
+ >>> aggregator = lambda d: statistics.mean(d.values())
260
+ >>> my_compare_dicts = functools.partial(
261
+ ... compare_dicts, field_comparators=field_comparators, aggregator=aggregator
262
+ ... )
263
+ >>> my_compare_dicts(dict1, dict2)
264
+ 1
265
+ >>> my_compare_dicts(dict1, dict3)
266
+ 0.5
267
+
268
+ """
269
+ common_keys = [k for k in dict1.keys() if k in dict2.keys()]
270
+
271
+ comparisons = {}
272
+ for key in common_keys:
273
+ comparator = field_comparators.get(key, default_comparator)
274
+ comparisons[key] = comparator(dict1[key], dict2[key])
275
+
276
+ return aggregator(comparisons)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lkj
3
- Version: 0.1.39
3
+ Version: 0.1.40
4
4
  Summary: A dump of homeless useful utils
5
5
  Home-page: https://github.com/thorwhalen/lkj
6
6
  Author: Thor Whalen
@@ -1,6 +1,6 @@
1
1
  lkj/__init__.py,sha256=YEPCVj-0EJOfpapgX3Vw07399w13OkCm39KCmCi5AQg,6806
2
2
  lkj/chunking.py,sha256=RpNdx5jEuO4mFg2qoTkD47iL35neBneuZ5xgQ_cBkiM,3755
3
- lkj/dicts.py,sha256=EbTLtYlexCDhDlwKnzflZ5CEU0ql6KgZdu3SvR7bU20,8289
3
+ lkj/dicts.py,sha256=nfciX_h7tplR3cbaDYcQvucb7UWzv8vmvp2NDEiQm-4,10227
4
4
  lkj/filesys.py,sha256=NbWDuc848h8O42gwX7d9yNJkrWBgzSFnkoEdSRgvBAg,8883
5
5
  lkj/funcs.py,sha256=LXJlj3gMMsbD0t2gn2NZZ6mOqmW5bxM-94uGoYgrhzI,8930
6
6
  lkj/importing.py,sha256=_BFBmdaKCBnk5broltWDeAPeEKG1dEkS8DhIdv6UhSI,3809
@@ -8,8 +8,8 @@ lkj/iterables.py,sha256=9jeO36w-IGiZryge7JKgXZOGZAgehUvhwKV3nHPcZWk,2801
8
8
  lkj/loggers.py,sha256=ImmBdacz89Lvb3dg_xI5jOct_44rSRv0hNI_CVehy60,13706
9
9
  lkj/misc.py,sha256=IZf05tkl0cgiMgBwCMH5cLSC59fRXwnemPRo8G0OxQg,1436
10
10
  lkj/strings.py,sha256=3YjlxOWUfzWqwu51uq_pv9XZReLqRFvziGtRsdzEtw8,24662
11
- lkj-0.1.39.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
12
- lkj-0.1.39.dist-info/METADATA,sha256=FFVXFg-ElX-E_xQRF9i8IExOOqEgIScsqigQTu0vtdM,4684
13
- lkj-0.1.39.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
14
- lkj-0.1.39.dist-info/top_level.txt,sha256=3DZOUwYmyurJFBXQCvCmEIVm8z2b42O5Sx3RDQyePfg,4
15
- lkj-0.1.39.dist-info/RECORD,,
11
+ lkj-0.1.40.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
12
+ lkj-0.1.40.dist-info/METADATA,sha256=MQn5N_4SfIm7fUZl9zCTtuSTz94PYPenG7EZd8juq14,4684
13
+ lkj-0.1.40.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
14
+ lkj-0.1.40.dist-info/top_level.txt,sha256=3DZOUwYmyurJFBXQCvCmEIVm8z2b42O5Sx3RDQyePfg,4
15
+ lkj-0.1.40.dist-info/RECORD,,
File without changes
File without changes