+def coalesce_by_creating_list(key, new_value, old_value):
+ from list_utils import flatten
+
+ return flatten([new_value, old_value])
+
+
+def coalesce_by_creating_set(key, new_value, old_value):
+ return set(coalesce_by_creating_list(key, new_value, old_value))
+
+
+def coalesce_last_write_wins(key, new_value, old_value):
+ return new_value
+
+
+def coalesce_first_write_wins(key, new_value, old_value):
+ return old_value
+
+
+def raise_on_duplicated_keys(key, new_value, old_value):
+ 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], Any] = coalesce_by_creating_list,
+) -> Dict[Any, Any]:
+ """Merge N dicts into one dict containing the union of all keys /
+ values in the input dicts. When keys collide, apply the
+ aggregation_function which, by default, creates a list of values.
+ See also several other alternative functions for coalescing values
+ (coalesce_by_creating_set, coalesce_first_write_wins,
+ coalesce_last_write_wins, raise_on_duplicated_keys) or provide a
+ custom helper function.
+
+ >>> a = {'a': 1, 'b': 2}
+ >>> b = {'b': 1, 'c': 2, 'd': 3}
+ >>> c = {'c': 1, 'd': 2}
+ >>> coalesce([a, b, c])
+ {'a': 1, 'b': [1, 2], 'c': [1, 2], 'd': [2, 3]}
+
+ >>> coalesce([a, b, c], aggregation_function=coalesce_last_write_wins)
+ {'a': 1, 'b': 1, 'c': 1, 'd': 2}
+
+ >>> coalesce([a, b, c], aggregation_function=raise_on_duplicated_keys)
+ Traceback (most recent call last):
+ ...
+ Exception: Key b is duplicated in more than one input dict.
+
+ """
+ out: Dict[Any, Any] = {}
+ for d in inputs:
+ for key in d:
+ if key in out:
+ value = aggregation_function(key, 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]:
+ """Returns the key and value with the max value in a dict.
+
+ >>> d = {'a': 1, 'b': 2, 'c': 3}
+ >>> item_with_max_value(d)
+ ('c', 3)
+ >>> item_with_max_value({})
+ Traceback (most recent call last):
+ ...
+ ValueError: max() arg is an empty sequence
+
+ """