""" Helper functions that does not fit in a specific module of the project """
import functools
from typing import Callable, Iterable

def cached_property(method: Callable):
    """Decorator meant to mimic Python 3.8's cached_property"""
    return property(functools.lru_cache()(method))

def find(collection, condition):
    """Return the first element in collection that satisfies condition"""
    return next((element for element in collection if condition(element)), None)

def group_by(values: Iterable, key: Callable, transform: Callable = None):
    """Receives an iterable object and return a dict grouping the elements
    whose the property generated by the 'key' argument are equal as a
    transformed element, if transform is not None"""
    if transform is None:
        transform = lambda item: item
    result: dict = {}
    for value in values:
        _key = key(value)
        result.setdefault(_key, [])
        result[_key].append(transform(value))
    return result
