""" Collection-related functions and utilities. """ import asyncio from collections import abc from typing import Any, Callable, Collection, Iterable def filter_values(mapping: dict, values: Collection) -> dict: """Filter dictionary by values. Args: mapping: Dictionary to filter. values: Values to filter out. Returns: dict: Filtered dictionary. Example: >>> sample_data = {"a": 1, "b": 2, "c": 3} >>> filter_values(sample_data, [1, 3]) {"b": 2} """ return {k: v for k, v in mapping.items() if v not in set(values)} def group_dicts_by_type( dicts: Collection[dict], type_key: str, k_key: str, v_key: str, ) -> dict[abc.Hashable, dict[abc.Hashable, Any]]: """Group a collection of dictionaries by their 'type' key. Args: dicts: Collection of dictionaries. type_key: Key to group by. k_key: Key to use as the key in the inner dictionary. v_key: Key to use as the value in the inner dictionary. Returns: dict[str, dict[str, str]]: Grouped dictionaries. Example: >>> sample_data = [ ... {"type": "A", "k": "a1", "v": "v1"}, ... {"type": "A", "k": "a2", "v": "v2"}, ... {"type": "B", "k": "b1", "v": "v1"}, ... ] >>> group_dicts_by_type(sample_data, "type", "k", "v") { "A": {"a1": "v1", "a2": "v2"}, "B": {"b1": "v1"}, } """ grouped = {} for item in dicts: grouped.setdefault(item[type_key], {})[item[k_key]] = item[v_key] return grouped async def async_dict( func: Callable[[abc.Hashable], Any], keys: Iterable[abc.Hashable] ) -> dict[abc.Hashable, Any]: """Asynchronously fetch values for a collection of keys and return them as a dictionary. Args: func: Asynchronous function to fetch values. Must accept a single key as an argument, which will be one of the keys provided. keys: Collection of keys to fetch values for. They will be automatically deduplicated and needn't be ordered when passed. Returns: dict: Dictionary of fetched values, keyed by the input keys. """ ordered_unique_keys = tuple(set(keys)) tasks = (func(key) for key in ordered_unique_keys) results = await asyncio.gather(*tasks) return dict(zip(ordered_unique_keys, results))