Various changes.
[python_utils.git] / dict_utils.py
index 29a5cd0c5b10fb84a61d078698109b8ebd31ffb6..74e8fdab22749917f21ae88c150b838120bb0820 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 
 from itertools import islice
-from typing import Any, Callable, Dict, Iterator
+from typing import Any, Callable, Dict, Iterator, Tuple
 
 
 def init_or_inc(
@@ -24,11 +24,40 @@ def shard(d: Dict[Any, Any], size: int) -> Iterator[Dict[Any, Any]]:
         yield {key: value for (key, value) in islice(items, x, x + size)}
 
 
-def item_with_max_value(d: Dict[Any, Any]) -> Any:
+def coalesce_by_creating_list(key, v1, v2):
+    from list_utils import flatten
+    return flatten([v1, v2])
+
+
+def coalesce_by_creating_set(key, v1, v2):
+    return set(coalesce_by_creating_list(key, v1, v2))
+
+
+def raise_on_duplicated_keys(key, v1, v2):
+    raise Exception(f'Key {key} is duplicated in more than one input dict.')
+
+
+def coalesce(
+        inputs: Iterator[Dict[Any, Any]],
+        *,
+        aggregation_function: Callable[[Any, Any], Any] = coalesce_by_creating_list
+) -> Dict[Any, Any]:
+    out: Dict[Any, Any] = {}
+    for d in inputs:
+        for key in d:
+            if key in out:
+                value = aggregation_function(d[key], out[key])
+            else:
+                value = d[key]
+            out[key] = value
+    return out
+
+
+def item_with_max_value(d: Dict[Any, Any]) -> Tuple[Any, Any]:
     return max(d.items(), key=lambda _: _[1])
 
 
-def item_with_min_value(d: Dict[Any, Any]) -> Any:
+def item_with_min_value(d: Dict[Any, Any]) -> Tuple[Any, Any]:
     return min(d.items(), key=lambda _: _[1])
 
 
@@ -54,19 +83,3 @@ def max_key(d: Dict[Any, Any]) -> Any:
 
 def min_key(d: Dict[Any, Any]) -> Any:
     return min(d.keys())
-
-
-def merge(a: Dict[Any, Any], b: Dict[Any, Any], path=None) -> Dict[Any, Any]:
-    if path is None:
-        path = []
-    for key in b:
-        if key in a:
-            if isinstance(a[key], dict) and isinstance(b[key], dict):
-                merge(a[key], b[key], path + [str(key)])
-            elif a[key] == b[key]:
-                pass
-            else:
-                raise Exception("Conflict at %s" % ".".join(path + [str(key)]))
-        else:
-            a[key] = b[key]
-    return a