"""This module contains helper functions for dealing with Python dictionaries."""
from itertools import islice
-from typing import Any, Callable, Dict, Iterator, List, Tuple
+from typing import Any, Callable, Dict, Hashable, Iterator, List, Tuple
from pyutils import dataclass_utils
+from pyutils.typez.typing import Comparable
+
+AnyDict = Dict[Hashable, Any]
+DictWithComparableKeys = Dict[Comparable, Any]
def init_or_inc(
- d: Dict[Any, Any],
- key: Any,
+ d: AnyDict,
+ key: Hashable,
*,
init_value: Any = 1,
inc_function: Callable[..., Any] = lambda x: x + 1,
) -> bool:
- """
- Initialize a dict value (if it doesn't exist) or increments it (using the
+ """Initialize a dict value (if it doesn't exist) or increments it (using the
inc_function, which is customizable) if it already does exist.
+ See also :py:class:`defaultdict`
+ (https://docs.python.org/3/library/collections.html#collections.defaultdict)
+ for a more pythonic alternative.
+
Args:
d: the dict to increment or initialize a value in
key: the key to increment or initialize
- init_value: default initial value
+ init_value: default initial value (see also :meth:`dict.setdefault`)
inc_function: Callable use to increment a value
Returns:
False
>>> d
{'test': 2, 'ing': 1}
+
"""
if key in d.keys():
d[key] = inc_function(d[key])
return False
-def shard(d: Dict[Any, Any], size: int) -> Iterator[Dict[Any, Any]]:
+def shard(d: AnyDict, size: int) -> Iterator[AnyDict]:
"""
Shards (i.e. splits) a dict into N subdicts which, together,
contain all keys/values from the original unsharded dict.
def coalesce(
- inputs: Iterator[Dict[Any, Any]],
+ inputs: Iterator[AnyDict],
*,
aggregation_function: Callable[[Any, Any, Any], Any] = coalesce_by_creating_list,
-) -> Dict[Any, Any]:
+) -> AnyDict:
"""Coalesce (i.e. combine) N input dicts into one output dict
ontaining the union of all keys / values in every input dict.
When keys collide, apply the aggregation_function which, by
...
Exception: Key b is duplicated in more than one input dict.
"""
- out: Dict[Any, Any] = {}
+ out: AnyDict = {}
for d in inputs:
for key in d:
if key in out:
return out
-def item_with_max_value(d: Dict[Any, Any]) -> Tuple[Any, Any]:
+def item_with_max_value(d: AnyDict) -> Tuple[Hashable, Any]:
"""
Args:
d: a dict with comparable values
return max(d.items(), key=lambda _: _[1])
-def item_with_min_value(d: Dict[Any, Any]) -> Tuple[Any, Any]:
+def item_with_min_value(d: AnyDict) -> Tuple[Hashable, Any]:
"""
Args:
d: a dict with comparable values
return min(d.items(), key=lambda _: _[1])
-def key_with_max_value(d: Dict[Any, Any]) -> Any:
+def key_with_max_value(d: AnyDict) -> Hashable:
"""
Args:
d: a dict with comparable keys
return item_with_max_value(d)[0]
-def key_with_min_value(d: Dict[Any, Any]) -> Any:
+def key_with_min_value(d: AnyDict) -> Hashable:
"""
Args:
d: a dict with comparable keys
return item_with_min_value(d)[0]
-def max_value(d: Dict[Any, Any]) -> Any:
+def max_value(d: AnyDict) -> Any:
"""
Args:
d: a dict with compatable values
return item_with_max_value(d)[1]
-def min_value(d: Dict[Any, Any]) -> Any:
+def min_value(d: AnyDict) -> Any:
"""
Args:
d: a dict with comparable values
return item_with_min_value(d)[1]
-def max_key(d: Dict[Any, Any]) -> Any:
+def max_key(d: DictWithComparableKeys) -> Comparable:
"""
Args:
d: a dict with comparable keys
return max(d.keys())
-def min_key(d: Dict[Any, Any]) -> Any:
+def min_key(d: DictWithComparableKeys) -> Comparable:
"""
Args:
d: a dict with comparable keys
return min(d.keys())
-def parallel_lists_to_dict(keys: List[Any], values: List[Any]) -> Dict[Any, Any]:
+def parallel_lists_to_dict(keys: List[Hashable], values: List[Any]) -> AnyDict:
"""Given two parallel lists (keys and values), create and return
a dict.
Returns:
A dict composed of zipping the keys list and values list together.
+ Raises:
+ ValueError: if keys and values lists not the same length.
+
>>> k = ['name', 'phone', 'address', 'zip']
>>> v = ['scott', '555-1212', '123 main st.', '12345']
>>> parallel_lists_to_dict(k, v)
{'name': 'scott', 'phone': '555-1212', 'address': '123 main st.', 'zip': '12345'}
"""
if len(keys) != len(values):
- raise Exception("Parallel keys and values lists must have the same length")
+ raise ValueError("Parallel keys and values lists must have the same length")
return dict(zip(keys, values))
-def dict_to_key_value_lists(d: Dict[Any, Any]) -> Tuple[List[Any], List[Any]]:
+def dict_to_key_value_lists(d: AnyDict) -> Tuple[List[Hashable], List[Any]]:
"""Given a dict, decompose it into a list of keys and values.
Args: