Source code for hbutils.collection.functional

"""
Overview:
    Function operations for nested structure.
    
    This module provides utilities for applying functions to nested data structures
    (lists, tuples, and dictionaries) in a recursive manner. It allows mapping operations
    over complex nested structures while preserving their original types and hierarchy.
"""
from ..reflection import dynamic_call

__all__ = [
    'nested_map'
]


[docs] def nested_map(f, s): """ Map the nested structure with a function. This function recursively traverses a nested structure (containing lists, tuples, and dictionaries) and applies the given function to each leaf value. The function can optionally accept the path to the current element as a parameter. :param f: The function to apply to each leaf value. Can accept 0, 1, or 2 parameters: - 0 params: Returns a constant value - 1 param: Receives the leaf value - 2 params: Receives the leaf value and its path (tuple of keys/indices) :type f: callable :param s: The nested structure to map over. Can be a dict, list, tuple, or any combination thereof, with leaf values of any type. :type s: dict or list or tuple or any :return: A new nested structure with the same type and hierarchy as the input, but with the function applied to all leaf values. :rtype: Same type as input structure Examples:: >>> from hbutils.collection import nested_map >>> nested_map(lambda x: x + 1, [ ... 2, 3, (4, {'x': 2, 'y': 4}), ... {'a': 3, 'b': (4, 5)}, ... ]) [3, 4, (5, {'x': 3, 'y': 5}), {'a': 4, 'b': (5, 6)}] >>> nested_map(lambda x, p: (x + 1) * len(p), [ ... 2, 3, (4, {'x': 2, 'y': 4}), ... {'a': 3, 'b': (4, 5)}, ... ]) [3, 4, (10, {'x': 9, 'y': 15}), {'a': 8, 'b': (15, 18)}] >>> nested_map(lambda: 233, [ ... 2, 3, (4, {'x': 2, 'y': 4}), ... {'a': 3, 'b': (4, 5)}, ... ]) [233, 233, (233, {'x': 233, 'y': 233}), {'a': 233, 'b': (233, 233)}] """ _df = dynamic_call(f) def _recursion(sval, p): """ Recursively traverse and map the nested structure. :param sval: The current value being processed :type sval: any :param p: The path to the current value (tuple of keys/indices) :type p: tuple :return: The mapped value or structure :rtype: any """ if isinstance(sval, dict): return type(sval)({k: _recursion(v, (*p, k)) for k, v in sval.items()}) elif isinstance(sval, (list, tuple)): return type(sval)(_recursion(v, (*p, i)) for i, v in enumerate(sval)) else: return _df(sval, p) return _recursion(s, ())