Beispiel #1
0
def partition(iteratee, seq):
    """
    Return a ``tuple`` of 2 lists containing elements from `seq` split into two groups where the
    first group contains all elements the `iteratee` returned truthy for and the second group
    containing the falsey elements.

    Examples:
        >>> partition(lambda x: x % 2, [1, 2, 3, 4])
        ([1, 3], [2, 4])

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to iterate over.

    Returns:
        tuple[list]
    """
    iteratee = fnc.iteratee(iteratee)
    successes = []
    failures = []

    for item in seq:
        if iteratee(item):
            successes.append(item)
        else:
            failures.append(item)

    return successes, failures
Beispiel #2
0
def groupby(iteratee, seq):
    """
    Return a ``dict`` composed of keys generated from the results of running each element of `seq`
    through the `iteratee`.

    Examples:
        >>> result = groupby('a', [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}])
        >>> result == {1: [{'a': 1, 'b': 2}], 3: [{'a': 3, 'b': 4}]}
        True
        >>> result = groupby({'a': 1}, [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}])
        >>> result == {False: [{'a': 3, 'b': 4}], True: [{'a': 1, 'b': 2}]}
        True

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to iterate over.

    Returns:
        dict: Results of grouping by `iteratee`.
    """
    result = {}
    iteratee = fnc.iteratee(iteratee)

    for item in seq:
        result.setdefault(iteratee(item), []).append(item)

    return result
Beispiel #3
0
def map(iteratee, *seqs):
    """
    Map `iteratee` to each element of iterable and yield the results. If additional iterable
    arguments are passed, `iteratee` must take that many arguments and is applied to the items from
    all iterables in parallel.

    Note:
        This function is like the builtin ``map`` except it converts `iteratee` into a
        fnc-style predicate.

    Examples:
        >>> list(map(str, [1, 2, 3, 4]))
        ['1', '2', '3', '4']
        >>> list(map('a', [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}, {'a': 5, 'b': 6}]))
        [1, 3, 5]
        >>> list(map('0.1', [[[0, 1]], [[2, 3]], [[4, 5]]]))
        [1, 3, 5]
        >>> list(map('a.b', [{'a': {'b': 1}}, {'a': {'b': 2}}]))
        [1, 2]
        >>> list(map('a.b[1]', [{'a': {'b': [0, 1]}}, {'a': {'b': [2, 3]}}]))
        [1, 3]

    Args:
        iteratee (object): Iteratee applied per iteration.
        *seqs (Iterable): Iterables to map.

    Yields:
        Mapped elements.
    """
    return _map(fnc.iteratee(iteratee), *seqs)
Beispiel #4
0
def intersectionby(iteratee, seq, *seqs):
    """
    Like :func:`intersection` except that an `iteratee` is used to modify each element in the
    sequences. The modified values are then used for comparison.

    Note:
        This function is like ``set.intersection()`` except it works with both hashable
        and unhashable values and preserves the ordering of the original iterables.

    Examples:
        >>> list(intersectionby(
        ...     'a',
        ...     [{'a': 1}, {'a': 2}, {'a': 3}],
        ...     [{'a': 1}, {'a': 2}, {'a': 3}, {'a': 4}, {'a': 5}],
        ...     [{'a': 2}, {'a': 3}]
        ... ))
        [{'a': 2}, {'a': 3}]

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to compute intersection against.
        *seqs (Iterable): Other iterables to compare with.

    Yields:
        Elements that intersect.
    """
    if not seqs:
        yield from unionby(iteratee, seq)
        return

    if iteratee is not None:
        iteratee = fnc.iteratee(iteratee)

    yielded = Container()
    # Map iteratee to each item in each other sequence and compute intersection of those
    # values to reduce number of times iteratee is called. The resulting sequence will
    # be an intersection of computed values which will be used to compare to the primary
    # sequence. We'll store these values into a iterable in case any of the sequences
    # are a generator/iterator that would get exhausted if we tried to iterate over it
    # more than once.
    others = Container(intersection(*(map(iteratee, other) for other in seqs)))

    for item in seq:
        if iteratee is not None:
            value = iteratee(item)
        else:
            value = item

        if value in yielded:
            continue

        if value in others:
            yield item
            yielded.add(value)
Beispiel #5
0
def differenceby(iteratee, seq, *seqs):
    """
    Like :func:`difference` except that an `iteratee` is used to modify each element in the
    sequences. The modified values are then used for comparison.

    Note:
        This function is like ``set.difference()`` except it works with both hashable
        and unhashable values and preserves the ordering of the original iterables.

    Examples:
        >>> list(differenceby('a', [{'a': 1}, {'a': 2}, {'a': 3}], [{'a': 1}], [{'a': 2}]))
        [{'a': 3}]
        >>> list(differenceby(lambda x: x % 4, [1, 4, 2, 3, 5, 0], [1], [2, 0]))
        [3]

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to compute difference against.
        *seqs (Iterable): Other iterables to compare with.

    Yields:
        Each element in `seq` that doesn't appear in `seqs`.
    """
    if not seqs:
        yield from unionby(iteratee, seq)
        return

    if iteratee is not None:
        iteratee = fnc.iteratee(iteratee)

    yielded = Container()
    # Concat sequences into a single sequence and map iteratee to each item so that the
    # computed value only needs to be done once for each item since that is what we'll
    # compare to below. We'll store these values into a iterable in case any of the
    # sequences are a generator/iterator that would get exhausted if we tried to iterate
    # over it more than once.
    others = Container(map(iteratee, concat(*seqs)))

    for item in seq:
        if iteratee is not None:
            value = iteratee(item)
        else:
            value = item

        if value in yielded or value in others:
            continue

        yield item
        yielded.add(value)
Beispiel #6
0
def mapkeys(iteratee, obj):
    """
    Return a ``dict`` with keys from `obj` mapped with `iteratee` while containing the same values.

    Examples:
        >>> result = mapkeys(lambda k: k * 2, {'a': 1, 'b': 2, 'c': 3})
        >>> result == {'aa': 1, 'bb': 2, 'cc': 3}
        True

    Args:
        iteratee (object): Iteratee applied to each key.
        obj (Mapping): Mapping to map.

    Returns:
        dict: Dictionary with mapped keys.
    """
    iteratee = fnc.iteratee(iteratee)
    return {iteratee(key): value for key, value in iterate(obj)}
Beispiel #7
0
def keyby(iteratee, seq):
    """
    Return a ``dict`` composed of keys generated from the results of running each element of `seq`
    through the `iteratee`.

    Examples:
        >>> results = keyby('a', [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}])
        >>> results == {1: {'a': 1, 'b': 2}, 3: {'a': 3, 'b': 4}}
        True

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to iterate over.

    Returns:
        dict: Results of indexing by `iteratee`.
    """
    iteratee = fnc.iteratee(iteratee)
    return {iteratee(value): value for value in seq}
Beispiel #8
0
def findindex(iteratee, seq):
    """
    Return the index of the element in `seq` that returns ``True`` for `iteratee`. If no match is
    found, ``-1`` is returned.

    Examples:
        >>> findindex(lambda x: x >= 3, [1, 2, 3, 4])
        2
        >>> findindex(lambda x: x > 4, [1, 2, 3, 4])
        -1

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to process.

    Returns:
        int: Index of found item or ``-1`` if not found.
    """
    iteratee = fnc.iteratee(iteratee)
    return next((i for i, value in enumerate(seq) if iteratee(value)), -1)
Beispiel #9
0
def mapvalues(iteratee, obj):
    """
    Return a ``dict`` with values from `obj` mapped with `iteratee` while containing the same keys.

    Examples:
        >>> result = mapvalues(lambda v: v * 2, {'a': 1, 'b': 2, 'c': 3})
        >>> result == {'a': 2, 'b': 4, 'c': 6}
        True
        >>> result = mapvalues({'d': 4}, {'a': 1, 'b': {'d': 4}, 'c': 3})
        >>> result == {'a': False, 'b': True, 'c': False}
        True

    Args:
        iteratee (object): Iteratee applied to each key.
        obj (Mapping): Mapping to map.

    Returns:
        dict: Dictionary with mapped values.
    """
    iteratee = fnc.iteratee(iteratee)
    return {key: iteratee(value) for key, value in iterate(obj)}
Beispiel #10
0
def unionby(iteratee, seq, *seqs):
    """
    Like :func:`union` except that an `iteratee` is used to modify each element in the sequences.
    The modified values are then used for comparison.

    Note:
        This function is like ``set.union()`` except it works with both hashable and
        unhashable values and preserves the ordering of the original iterables.

    Examples:
        >>> list(unionby(
        ...     'a',
        ...     [{'a': 1}, {'a': 2}, {'a': 3}, {'a': 1}, {'a': 2}, {'a': 3}]
        ... ))
        [{'a': 1}, {'a': 2}, {'a': 3}]

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to compute union against.
        *seqs (Iterable): Other iterables to compare with.

    Yields:
        Each unique element from all iterables.
    """
    if iteratee is not None:
        iteratee = fnc.iteratee(iteratee)

    seen = Container()

    for item in itertools.chain(seq, *seqs):
        if iteratee is not None:
            value = iteratee(item)
        else:
            value = item

        if value not in seen:
            yield item

        seen.add(value)
Beispiel #11
0
def reject(iteratee, seq):
    """
    The opposite of :func:`filter` this function yields the elements of `seq` that the `iteratee`
    returns falsey for.

    Examples:
        >>> list(reject(lambda x: x >= 3, [1, 2, 3, 4]))
        [1, 2]
        >>> list(reject('a', [{'a': 0}, {'a': 1}, {'a': 2}]))
        [{'a': 0}]
        >>> list(reject({'a': 1}, [{'a': 0}, {'a': 1}, {'a': 2}]))
        [{'a': 0}, {'a': 2}]

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to iterate over.

    Yields:
        Rejected elements.
    """
    iteratee = fnc.iteratee(iteratee)
    return filter(fnc.compose(iteratee, not_), seq)
Beispiel #12
0
def filter(iteratee, seq):
    """
    Filter `seq` by `iteratee`, yielding only the elements that the iteratee returns truthy for.

    Note:
        This function is like the builtin ``filter`` except it converts `iteratee` into
        a fnc-style predicate.

    Examples:
        >>> result = filter({'a': 1}, [{'a': 1}, {'b': 2}, {'a': 1, 'b': 3}])
        >>> list(result) == [{'a': 1}, {'a': 1, 'b': 3}]
        True
        >>> list(filter(lambda x: x >= 3, [1, 2, 3, 4]))
        [3, 4]

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to filter.

    Yields:
        Filtered elements.
    """
    return _filter(fnc.iteratee(iteratee), seq)
Beispiel #13
0
def duplicatesby(iteratee, seq, *seqs):
    """
    Like :func:`duplicates` except that an `iteratee` is used to modify each element in the
    sequences. The modified values are then used for comparison.

    Examples:
        >>> list(duplicatesby('a', [{'a':1}, {'a':3}, {'a':2}, {'a':3}, {'a':1}]))
        [{'a': 3}, {'a': 1}]

    Args:
        iteratee (object): Iteratee applied per iteration.
        seq (Iterable): Iterable to check for duplicates
        *seqs (Iterable): Other iterables to compare with.

    Yields:
        Each element in `seq` that doesn't appear in `seqs`.
    """
    if iteratee is not None:
        iteratee = fnc.iteratee(iteratee)

    seen = Container()
    yielded = Container()

    for item in itertools.chain(seq, *seqs):
        if iteratee is not None:
            value = iteratee(item)
        else:
            value = item

        if value not in seen:
            seen.add(value)
            continue

        if value not in yielded:
            yield item
            yielded.add(value)
Beispiel #14
0
def test_iteratee(case):
    args = case["args"]
    assert fnc.iteratee(args[0])(*args[1:]) == case["expected"]