"""
Functions that operate on lists and dicts.
.. versionadded:: 1.0.0
"""
from __future__ import annotations
from functools import cmp_to_key
import random
import typing as t
import pydash as pyd
from .helpers import callit, cmp, getargcount, iterator, iteriteratee
from .types import IterateeObjT, PathT
__all__ = (
"at",
"count_by",
"every",
"filter_",
"find",
"find_last",
"flat_map",
"flat_map_deep",
"flat_map_depth",
"for_each",
"for_each_right",
"group_by",
"includes",
"invoke_map",
"key_by",
"map_",
"nest",
"order_by",
"partition",
"pluck",
"reduce_",
"reduce_right",
"reductions",
"reductions_right",
"reject",
"sample",
"sample_size",
"shuffle",
"size",
"some",
"sort_by",
)
T = t.TypeVar("T")
T2 = t.TypeVar("T2")
T3 = t.TypeVar("T3")
T4 = t.TypeVar("T4")
@t.overload
def at(collection: t.Mapping[T, T2], *paths: T) -> t.List[t.Union[T2, None]]: ...
@t.overload
def at(collection: t.Mapping[T, t.Any], *paths: t.Union[T, t.Iterable[T]]) -> t.List[t.Any]: ...
@t.overload
def at(collection: t.Iterable[T], *paths: int) -> t.List[t.Union[T, None]]: ...
@t.overload
def at(collection: t.Iterable[t.Any], *paths: t.Union[int, t.Iterable[int]]) -> t.List[t.Any]: ...
[docs]
def at(collection, *paths):
"""
Creates a list of elements from the specified indexes, or keys, of the collection. Indexes may
be specified as individual arguments or as arrays of indexes.
Args:
collection: Collection to iterate over.
*paths: The indexes of `collection` to retrieve, specified as individual indexes or
arrays of indexes.
Returns:
filtered list
Example:
>>> at([1, 2, 3, 4], 0, 2)
[1, 3]
>>> at({"a": 1, "b": 2, "c": 3, "d": 4}, "a", "c")
[1, 3]
>>> at({"a": 1, "b": 2, "c": {"d": {"e": 3}}}, "a", ["c", "d", "e"])
[1, 3]
.. versionadded:: 1.0.0
.. versionchanged:: 4.1.0
Support deep path access.
"""
return pyd.properties(*paths)(collection)
@t.overload
def count_by(collection: t.Mapping[t.Any, T2], iteratee: None = None) -> t.Dict[T2, int]: ...
@t.overload
def count_by(
collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], T3]
) -> t.Dict[T3, int]: ...
@t.overload
def count_by(
collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], T3]
) -> t.Dict[T3, int]: ...
@t.overload
def count_by(
collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], T3]
) -> t.Dict[T3, int]: ...
@t.overload
def count_by(collection: t.Iterable[T], iteratee: None = None) -> t.Dict[T, int]: ...
@t.overload
def count_by(
collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], T2]
) -> t.Dict[T2, int]: ...
@t.overload
def count_by(collection: t.Iterable[T], iteratee: t.Callable[[T, int], T2]) -> t.Dict[T2, int]: ...
@t.overload
def count_by(collection: t.Iterable[T], iteratee: t.Callable[[T], T2]) -> t.Dict[T2, int]: ...
[docs]
def count_by(collection, iteratee=None):
"""
Creates an object composed of keys generated from the results of running each element of
`collection` through the iteratee.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
Returns:
Dict containing counts by key.
Example:
>>> results = count_by([1, 2, 1, 2, 3, 4])
>>> assert results == {1: 2, 2: 2, 3: 1, 4: 1}
>>> results = count_by(["a", "A", "B", "b"], lambda x: x.lower())
>>> assert results == {"a": 2, "b": 2}
>>> results = count_by({"a": 1, "b": 1, "c": 3, "d": 3})
>>> assert results == {1: 2, 3: 2}
.. versionadded:: 1.0.0
"""
ret = {}
for result in iteriteratee(collection, iteratee):
ret.setdefault(result[0], 0)
ret[result[0]] += 1
return ret
[docs]
def every(
collection: t.Iterable[T], predicate: t.Union[t.Callable[[T], t.Any], IterateeObjT, None] = None
) -> bool:
"""
Checks if the predicate returns a truthy value for all elements of a collection. The predicate
is invoked with three arguments: ``(value, index|key, collection)``. If a property name is
passed for predicate, the created :func:`pluck` style predicate will return the property value
of the given element. If an object is passed for predicate, the created :func:`.matches` style
predicate will return ``True`` for elements that have the properties of the given object, else
``False``.
Args:
collection: Collection to iterate over.
predicate: Predicate applied per iteration.
Returns:
Whether all elements are truthy.
Example:
>>> every([1, True, "hello"])
True
>>> every([1, False, "hello"])
False
>>> every([{"a": 1}, {"a": True}, {"a": "hello"}], "a")
True
>>> every([{"a": 1}, {"a": False}, {"a": "hello"}], "a")
False
>>> every([{"a": 1}, {"a": 1}], {"a": 1})
True
>>> every([{"a": 1}, {"a": 2}], {"a": 1})
False
.. versionadded:: 1.0.0
.. versionchanged: 4.0.0
Removed alias ``all_``.
"""
if predicate:
cbk = pyd.iteratee(predicate)
collection = (cbk(item) for item in collection)
return all(collection)
@t.overload
def filter_(
collection: t.Mapping[T, T2],
predicate: t.Union[t.Callable[[T2, T, t.Dict[T, T2]], t.Any], IterateeObjT, None] = None,
) -> t.List[T2]: ...
@t.overload
def filter_(
collection: t.Mapping[T, T2],
predicate: t.Union[t.Callable[[T2, T], t.Any], IterateeObjT, None] = None,
) -> t.List[T2]: ...
@t.overload
def filter_(
collection: t.Mapping[t.Any, T2],
predicate: t.Union[t.Callable[[T2], t.Any], IterateeObjT, None] = None,
) -> t.List[T2]: ...
@t.overload
def filter_(
collection: t.Iterable[T],
predicate: t.Union[t.Callable[[T, int, t.List[T]], t.Any], IterateeObjT, None] = None,
) -> t.List[T]: ...
@t.overload
def filter_(
collection: t.Iterable[T],
predicate: t.Union[t.Callable[[T, int], t.Any], IterateeObjT, None] = None,
) -> t.List[T]: ...
@t.overload
def filter_(
collection: t.Iterable[T],
predicate: t.Union[t.Callable[[T], t.Any], IterateeObjT, None] = None,
) -> t.List[T]: ...
[docs]
def filter_(collection, predicate=None):
"""
Iterates over elements of a collection, returning a list of all elements the predicate returns
truthy for.
Args:
collection: Collection to iterate over.
predicate: Predicate applied per iteration.
Returns:
Filtered list.
Example:
>>> results = filter_([{"a": 1}, {"b": 2}, {"a": 1, "b": 3}], {"a": 1})
>>> assert results == [{"a": 1}, {"a": 1, "b": 3}]
>>> filter_([1, 2, 3, 4], lambda x: x >= 3)
[3, 4]
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Removed alias ``select``.
"""
return [value for is_true, value, _, _ in iteriteratee(collection, predicate) if is_true]
@t.overload
def find(
collection: t.Dict[T, T2],
predicate: t.Union[t.Callable[[T2, T, t.Dict[T, T2]], t.Any], IterateeObjT, None] = None,
) -> t.Union[T2, None]: ...
@t.overload
def find(
collection: t.Dict[T, T2],
predicate: t.Union[t.Callable[[T2, T], t.Any], IterateeObjT, None] = None,
) -> t.Union[T2, None]: ...
@t.overload
def find(
collection: t.Dict[T, T2],
predicate: t.Union[t.Callable[[T2], t.Any], IterateeObjT, None] = None,
) -> t.Union[T2, None]: ...
@t.overload
def find(
collection: t.List[T],
predicate: t.Union[t.Callable[[T, int, t.List[T]], t.Any], IterateeObjT, None] = None,
) -> t.Union[T, None]: ...
@t.overload
def find(
collection: t.List[T],
predicate: t.Union[t.Callable[[T, int], t.Any], IterateeObjT, None] = None,
) -> t.Union[T, None]: ...
@t.overload
def find(
collection: t.List[T],
predicate: t.Union[t.Callable[[T], t.Any], IterateeObjT, None] = None,
) -> t.Union[T, None]: ...
[docs]
def find(collection, predicate=None):
"""
Iterates over elements of a collection, returning the first element that the predicate returns
truthy for.
Args:
collection: Collection to iterate over.
predicate: Predicate applied per iteration.
Returns:
First element found or ``None``.
Example:
>>> find([1, 2, 3, 4], lambda x: x >= 3)
3
>>> find([{"a": 1}, {"b": 2}, {"a": 1, "b": 2}], {"a": 1})
{'a': 1}
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Removed aliases ``detect`` and ``find_where``.
"""
search = (value for is_true, value, _, _ in iteriteratee(collection, predicate) if is_true)
return next(search, None)
@t.overload
def find_last(
collection: t.Dict[T, T2],
predicate: t.Union[t.Callable[[T2, T, t.Dict[T, T2]], t.Any], IterateeObjT, None] = None,
) -> t.Union[T2, None]: ...
@t.overload
def find_last(
collection: t.Dict[T, T2],
predicate: t.Union[t.Callable[[T2, T], t.Any], IterateeObjT, None] = None,
) -> t.Union[T2, None]: ...
@t.overload
def find_last(
collection: t.Dict[t.Any, T2],
predicate: t.Union[t.Callable[[T2], t.Any], IterateeObjT, None] = None,
) -> t.Union[T2, None]: ...
@t.overload
def find_last(
collection: t.List[T],
predicate: t.Union[t.Callable[[T, int, t.List[T]], t.Any], IterateeObjT, None] = None,
) -> t.Union[T, None]: ...
@t.overload
def find_last(
collection: t.List[T],
predicate: t.Union[t.Callable[[T, int], t.Any], IterateeObjT, None] = None,
) -> t.Union[T, None]: ...
@t.overload
def find_last(
collection: t.List[T],
predicate: t.Union[t.Callable[[T], t.Any], IterateeObjT, None] = None,
) -> t.Union[T, None]: ...
[docs]
def find_last(collection, predicate=None):
"""
This method is like :func:`find` except that it iterates over elements of a `collection` from
right to left.
Args:
collection: Collection to iterate over.
predicate: Predicate applied per iteration.
Returns:
Last element found or ``None``.
Example:
>>> find_last([1, 2, 3, 4], lambda x: x >= 3)
4
>>> results = find_last([{'a': 1}, {'b': 2}, {'a': 1, 'b': 2}],\
{'a': 1})
>>> assert results == {'a': 1, 'b': 2}
.. versionadded:: 1.0.0
"""
search = (
value
for is_true, value, _, _ in iteriteratee(collection, predicate, reverse=True)
if is_true
)
return next(search, None)
@t.overload
def flat_map(
collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], t.Iterable[T3]]
) -> t.List[T3]: ...
@t.overload
def flat_map(
collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], t.Iterable[T3]]
) -> t.List[T3]: ...
@t.overload
def flat_map(
collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], t.Iterable[T3]]
) -> t.List[T3]: ...
@t.overload
def flat_map(
collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], T3]
) -> t.List[T3]: ...
@t.overload
def flat_map(collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], T3]) -> t.List[T3]: ...
@t.overload
def flat_map(collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], T3]) -> t.List[T3]: ...
@t.overload
def flat_map(collection: t.Mapping[t.Any, t.Iterable[T2]], iteratee: None = None) -> t.List[T2]: ...
@t.overload
def flat_map(collection: t.Mapping[t.Any, T2], iteratee: None = None) -> t.List[T2]: ...
@t.overload
def flat_map(
collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], t.Iterable[T2]]
) -> t.List[T2]: ...
@t.overload
def flat_map(
collection: t.Iterable[T], iteratee: t.Callable[[T, int], t.Iterable[T2]]
) -> t.List[T2]: ...
@t.overload
def flat_map(
collection: t.Iterable[T], iteratee: t.Callable[[T], t.Iterable[T2]]
) -> t.List[T2]: ...
@t.overload
def flat_map(
collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], T2]
) -> t.List[T2]: ...
@t.overload
def flat_map(collection: t.Iterable[T], iteratee: t.Callable[[T, int], T2]) -> t.List[T2]: ...
@t.overload
def flat_map(collection: t.Iterable[T], iteratee: t.Callable[[T], T2]) -> t.List[T2]: ...
@t.overload
def flat_map(collection: t.Iterable[t.Iterable[T]], iteratee: None = None) -> t.List[T]: ...
@t.overload
def flat_map(collection: t.Iterable[T], iteratee: None = None) -> t.List[T]: ...
[docs]
def flat_map(collection, iteratee=None):
"""
Creates a flattened list of values by running each element in collection through `iteratee` and
flattening the mapped results. The `iteratee` is invoked with three arguments: ``(value,
index|key, collection)``.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
Returns:
Flattened mapped list.
Example:
>>> duplicate = lambda n: [[n, n]]
>>> flat_map([1, 2], duplicate)
[[1, 1], [2, 2]]
.. versionadded:: 4.0.0
"""
return pyd.flatten(itermap(collection, iteratee=iteratee))
@t.overload
def flat_map_deep(
collection: t.Mapping[T, T2],
iteratee: t.Union[t.Callable[[T2, T, t.Dict[T, T2]], t.Any], None] = None,
) -> t.List[t.Any]: ...
@t.overload
def flat_map_deep(
collection: t.Mapping[T, T2], iteratee: t.Union[t.Callable[[T2, T], t.Any], None] = None
) -> t.List[t.Any]: ...
@t.overload
def flat_map_deep(
collection: t.Mapping[t.Any, T2], iteratee: t.Union[t.Callable[[T2], t.Any], None] = None
) -> t.List[t.Any]: ...
@t.overload
def flat_map_deep(
collection: t.Iterable[T],
iteratee: t.Union[t.Callable[[T, int, t.List[T]], t.Any], None] = None,
) -> t.List[t.Any]: ...
@t.overload
def flat_map_deep(
collection: t.Iterable[T], iteratee: t.Union[t.Callable[[T, int], t.Any], None] = None
) -> t.List[t.Any]: ...
@t.overload
def flat_map_deep(
collection: t.Iterable[T], iteratee: t.Union[t.Callable[[T], t.Any], None] = None
) -> t.List[t.Any]: ...
[docs]
def flat_map_deep(collection, iteratee=None):
"""
This method is like :func:`flat_map` except that it recursively flattens the mapped results.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
Returns:
Flattened mapped list.
Example:
>>> duplicate = lambda n: [[n, n]]
>>> flat_map_deep([1, 2], duplicate)
[1, 1, 2, 2]
.. versionadded:: 4.0.0
"""
return pyd.flatten_deep(itermap(collection, iteratee=iteratee))
@t.overload
def flat_map_depth(
collection: t.Mapping[T, T2],
iteratee: t.Union[t.Callable[[T2, T, t.Dict[T, T2]], t.Any], None] = None,
depth: int = 1,
) -> t.List[t.Any]: ...
@t.overload
def flat_map_depth(
collection: t.Mapping[T, T2],
iteratee: t.Union[t.Callable[[T2, T], t.Any], None] = None,
depth: int = 1,
) -> t.List[t.Any]: ...
@t.overload
def flat_map_depth(
collection: t.Mapping[t.Any, T2],
iteratee: t.Union[t.Callable[[T2], t.Any], None] = None,
depth: int = 1,
) -> t.List[t.Any]: ...
@t.overload
def flat_map_depth(
collection: t.Iterable[T],
iteratee: t.Union[t.Callable[[T, int, t.List[T]], t.Any], None] = None,
depth: int = 1,
) -> t.List[t.Any]: ...
@t.overload
def flat_map_depth(
collection: t.Iterable[T],
iteratee: t.Union[t.Callable[[T, int], t.Any], None] = None,
depth: int = 1,
) -> t.List[t.Any]: ...
@t.overload
def flat_map_depth(
collection: t.Iterable[T],
iteratee: t.Union[t.Callable[[T], t.Any], None] = None,
depth: int = 1,
) -> t.List[t.Any]: ...
[docs]
def flat_map_depth(collection, iteratee=None, depth=1):
"""
This method is like :func:`flat_map` except that it recursively flattens the mapped results up
to `depth` times.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
Returns:
Flattened mapped list.
Example:
>>> duplicate = lambda n: [[n, n]]
>>> flat_map_depth([1, 2], duplicate, 1)
[[1, 1], [2, 2]]
>>> flat_map_depth([1, 2], duplicate, 2)
[1, 1, 2, 2]
.. versionadded:: 4.0.0
"""
return pyd.flatten_depth(itermap(collection, iteratee=iteratee), depth=depth)
@t.overload
def for_each(
collection: t.Dict[T, T2],
iteratee: t.Union[t.Callable[[T2, T, t.Dict[T, T2]], t.Any], IterateeObjT, None] = None,
) -> t.Dict[T, T2]: ...
@t.overload
def for_each(
collection: t.Dict[T, T2],
iteratee: t.Union[t.Callable[[T2, T], t.Any], IterateeObjT, None] = None,
) -> t.Dict[T, T2]: ...
@t.overload
def for_each(
collection: t.Dict[T, T2],
iteratee: t.Union[t.Callable[[T2], t.Any], IterateeObjT, None] = None,
) -> t.Dict[T, T2]: ...
@t.overload
def for_each(
collection: t.List[T],
iteratee: t.Union[t.Callable[[T, int, t.List[T]], t.Any], IterateeObjT, None] = None,
) -> t.List[T]: ...
@t.overload
def for_each(
collection: t.List[T],
iteratee: t.Union[t.Callable[[T, int], t.Any], IterateeObjT, None] = None,
) -> t.List[T]: ...
@t.overload
def for_each(
collection: t.List[T],
iteratee: t.Union[t.Callable[[T], t.Any], IterateeObjT, None] = None,
) -> t.List[T]: ...
[docs]
def for_each(collection, iteratee=None):
"""
Iterates over elements of a collection, executing the iteratee for each element.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
Returns:
`collection`
Example:
>>> results = {}
>>> def cb(x):
... results[x] = x**2
>>> for_each([1, 2, 3, 4], cb)
[1, 2, 3, 4]
>>> assert results == {1: 1, 2: 4, 3: 9, 4: 16}
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Removed alias ``each``.
"""
next((None for ret, _, _, _ in iteriteratee(collection, iteratee) if ret is False), None)
return collection
@t.overload
def for_each_right(
collection: t.Dict[T, T2],
iteratee: t.Union[t.Callable[[T2, T, t.Dict[T, T2]], t.Any], IterateeObjT],
) -> t.Dict[T, T2]: ...
@t.overload
def for_each_right(
collection: t.Dict[T, T2],
iteratee: t.Union[t.Callable[[T2, T], t.Any], IterateeObjT],
) -> t.Dict[T, T2]: ...
@t.overload
def for_each_right(
collection: t.Dict[T, T2],
iteratee: t.Union[t.Callable[[T2], t.Any], IterateeObjT],
) -> t.Dict[T, T2]: ...
@t.overload
def for_each_right(
collection: t.List[T],
iteratee: t.Union[t.Callable[[T, int, t.List[T]], t.Any], IterateeObjT],
) -> t.List[T]: ...
@t.overload
def for_each_right(
collection: t.List[T],
iteratee: t.Union[t.Callable[[T, int], t.Any], IterateeObjT],
) -> t.List[T]: ...
@t.overload
def for_each_right(
collection: t.List[T],
iteratee: t.Union[t.Callable[[T], t.Any], IterateeObjT],
) -> t.List[T]: ...
[docs]
def for_each_right(collection, iteratee):
"""
This method is like :func:`for_each` except that it iterates over elements of a `collection`
from right to left.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
Returns:
`collection`
Example:
>>> results = {"total": 1}
>>> def cb(x):
... results["total"] = x * results["total"]
>>> for_each_right([1, 2, 3, 4], cb)
[1, 2, 3, 4]
>>> assert results == {"total": 24}
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Removed alias ``each_right``.
"""
next(
(None for ret, _, _, _ in iteriteratee(collection, iteratee, reverse=True) if ret is False),
None,
)
return collection
@t.overload
def group_by(collection: t.Iterable[T], iteratee: t.Callable[[T], T2]) -> t.Dict[T2, t.List[T]]: ...
@t.overload
def group_by(
collection: t.Iterable[T], iteratee: t.Union[IterateeObjT, None] = None
) -> t.Dict[t.Any, t.List[T]]: ...
[docs]
def group_by(collection, iteratee=None):
"""
Creates an object composed of keys generated from the results of running each element of a
`collection` through the iteratee.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
Returns:
Results of grouping by `iteratee`.
Example:
>>> results = group_by([{'a': 1, 'b': 2}, {'a': 3, 'b': 4}], 'a')
>>> assert results == {1: [{'a': 1, 'b': 2}], 3: [{'a': 3, 'b': 4}]}
>>> results = group_by([{'a': 1, 'b': 2}, {'a': 3, 'b': 4}], {'a': 1})
>>> assert results == {False: [{'a': 3, 'b': 4}],\
True: [{'a': 1, 'b': 2}]}
.. versionadded:: 1.0.0
"""
ret = {}
cbk = pyd.iteratee(iteratee)
for value in collection:
key = cbk(value)
ret.setdefault(key, [])
ret[key].append(value)
return ret
[docs]
def includes(
collection: t.Union[t.Sequence[t.Any], t.Dict[t.Any, t.Any]], target: t.Any, from_index: int = 0
) -> bool:
"""
Checks if a given value is present in a collection. If `from_index` is negative, it is used as
the offset from the end of the collection.
Args:
collection: Collection to iterate over.
target: Target value to compare to.
from_index: Offset to start search from.
Returns:
Whether `target` is in `collection`.
Example:
>>> includes([1, 2, 3, 4], 2)
True
>>> includes([1, 2, 3, 4], 2, from_index=2)
False
>>> includes({"a": 1, "b": 2, "c": 3, "d": 4}, 2)
True
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Renamed from ``contains`` to ``includes`` and removed alias
``include``.
"""
collection_values: t.Container[t.Any]
if isinstance(collection, dict):
collection_values = collection.values()
else:
# only makes sense to do this if `collection` is not a dict
collection_values = collection[from_index:]
return target in collection_values
[docs]
def invoke_map(
collection: t.Iterable[t.Any], path: PathT, *args: t.Any, **kwargs: t.Any
) -> t.List[t.Any]:
"""
Invokes the method at `path` of each element in `collection`, returning a list of the results of
each invoked method. Any additional arguments are provided to each invoked method. If `path` is
a function, it's invoked for each element in `collection`.
Args:
collection: Collection to iterate over.
path: String path to method to invoke or callable to invoke for each element in
`collection`.
args: Arguments to pass to method call.
kwargs: Keyword arguments to pass to method call.
Returns:
List of results of invoking method of each item.
Example:
>>> items = [{"a": [{"b": 1}]}, {"a": [{"c": 2}]}]
>>> expected = [{"b": 1}.items(), {"c": 2}.items()]
>>> invoke_map(items, "a[0].items") == expected
True
.. versionadded:: 4.0.0
"""
return map_(collection, lambda item: pyd.invoke(item, path, *args, **kwargs))
@t.overload
def key_by(collection: t.Iterable[T], iteratee: t.Callable[[T], T2]) -> t.Dict[T2, T]: ...
@t.overload
def key_by(
collection: t.Iterable[t.Any], iteratee: t.Union[IterateeObjT, None] = None
) -> t.Dict[t.Any, t.Any]: ...
[docs]
def key_by(collection, iteratee=None):
"""
Creates an object composed of keys generated from the results of running each element of the
collection through the given iteratee.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
Returns:
Results of indexing by `iteratee`.
Example:
>>> results = key_by([{"a": 1, "b": 2}, {"a": 3, "b": 4}], "a")
>>> assert results == {1: {"a": 1, "b": 2}, 3: {"a": 3, "b": 4}}
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Renamed from ``index_by`` to ``key_by``.
"""
ret = {}
cbk = pyd.iteratee(iteratee)
for value in collection:
ret[cbk(value)] = value
return ret
@t.overload
def map_(collection: t.Mapping[t.Any, T2], iteratee: t.Callable[[T2], T3]) -> t.List[T3]: ...
@t.overload
def map_(collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T], T3]) -> t.List[T3]: ...
@t.overload
def map_(
collection: t.Mapping[T, T2], iteratee: t.Callable[[T2, T, t.Dict[T, T2]], T3]
) -> t.List[T3]: ...
@t.overload
def map_(collection: t.Iterable[T], iteratee: t.Callable[[T], T2]) -> t.List[T2]: ...
@t.overload
def map_(collection: t.Iterable[T], iteratee: t.Callable[[T, int], T2]) -> t.List[T2]: ...
@t.overload
def map_(
collection: t.Iterable[T], iteratee: t.Callable[[T, int, t.List[T]], T2]
) -> t.List[T2]: ...
@t.overload
def map_(
collection: t.Iterable[t.Any], iteratee: t.Union[IterateeObjT, None] = None
) -> t.List[t.Any]: ...
[docs]
def map_(collection, iteratee=None):
"""
Creates an array of values by running each element in the collection through the iteratee. The
iteratee is invoked with three arguments: ``(value, index|key, collection)``. If a property name
is passed for iteratee, the created :func:`pluck` style iteratee will return the property value
of the given element. If an object is passed for iteratee, the created :func:`.matches` style
iteratee will return ``True`` for elements that have the properties of the given object, else
``False``.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
Returns:
Mapped list.
Example:
>>> map_([1, 2, 3, 4], str)
['1', '2', '3', '4']
>>> map_([{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}], "a")
[1, 3, 5]
>>> map_([[[0, 1]], [[2, 3]], [[4, 5]]], "0.1")
[1, 3, 5]
>>> map_([{"a": {"b": 1}}, {"a": {"b": 2}}], "a.b")
[1, 2]
>>> map_([{"a": {"b": [0, 1]}}, {"a": {"b": [2, 3]}}], "a.b[1]")
[1, 3]
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Removed alias ``collect``.
"""
return list(itermap(collection, iteratee))
[docs]
def nest(collection: t.Iterable[t.Any], *properties: t.Any) -> t.Any:
"""
This method is like :func:`group_by` except that it supports nested grouping by multiple string
`properties`. If only a single key is given, it is like calling ``group_by(collection, prop)``.
Args:
collection: Collection to iterate over.
*properties: Properties to nest by.
Returns:
Results of nested grouping by `properties`.
Example:
>>> results = nest([{'shape': 'square', 'color': 'red', 'qty': 5},\
{'shape': 'square', 'color': 'blue', 'qty': 10},\
{'shape': 'square', 'color': 'orange', 'qty': 5},\
{'shape': 'circle', 'color': 'yellow', 'qty': 5},\
{'shape': 'circle', 'color': 'pink', 'qty': 10},\
{'shape': 'oval', 'color': 'purple', 'qty': 5}],\
'shape', 'qty')
>>> expected = {\
'square': {5: [{'shape': 'square', 'color': 'red', 'qty': 5},\
{'shape': 'square', 'color': 'orange', 'qty': 5}],\
10: [{'shape': 'square', 'color': 'blue', 'qty': 10}]},\
'circle': {5: [{'shape': 'circle', 'color': 'yellow', 'qty': 5}],\
10: [{'shape': 'circle', 'color': 'pink', 'qty': 10}]},\
'oval': {5: [{'shape': 'oval', 'color': 'purple', 'qty': 5}]}}
>>> results == expected
True
.. versionadded:: 4.3.0
"""
if not properties:
return collection
flat_properties = pyd.flatten(properties)
first, rest = flat_properties[0], flat_properties[1:]
return pyd.map_values(group_by(collection, first), lambda value: nest(value, *rest))
@t.overload
def order_by(
collection: t.Mapping[t.Any, T2],
keys: t.Iterable[t.Union[str, int]],
orders: t.Union[t.Iterable[bool], bool],
reverse: bool = False,
) -> t.List[T2]: ...
@t.overload
def order_by(
collection: t.Mapping[t.Any, T2],
keys: t.Iterable[str],
orders: None = None,
reverse: bool = False,
) -> t.List[T2]: ...
@t.overload
def order_by(
collection: t.Iterable[T],
keys: t.Iterable[t.Union[str, int]],
orders: t.Union[t.Iterable[bool], bool],
reverse: bool = False,
) -> t.List[T]: ...
@t.overload
def order_by(
collection: t.Iterable[T],
keys: t.Iterable[str],
orders: None = None,
reverse: bool = False,
) -> t.List[T]: ...
[docs]
def order_by(collection, keys, orders=None, reverse=False):
"""
This method is like :func:`sort_by` except that it sorts by key names instead of an iteratee
function. Keys can be sorted in descending order by prepending a ``"-"`` to the key name (e.g.
``"name"`` would become ``"-name"``) or by passing a list of boolean sort options via `orders`
where ``True`` is ascending and ``False`` is descending.
Args:
collection: Collection to iterate over.
keys: List of keys to sort by. By default, keys will be sorted in ascending order. To
sort a key in descending order, prepend a ``"-"`` to the key name. For example, to sort
the key value for ``"name"`` in descending order, use ``"-name"``.
orders: List of boolean sort orders to apply for each key. ``True``
corresponds to ascending order while ``False`` is descending. Defaults to ``None``.
reverse (bool, optional): Whether to reverse the sort. Defaults to ``False``.
Returns:
Sorted list.
Example:
>>> items = [{'a': 2, 'b': 1}, {'a': 3, 'b': 2}, {'a': 1, 'b': 3}]
>>> results = order_by(items, ['b', 'a'])
>>> assert results == [{'a': 2, 'b': 1},\
{'a': 3, 'b': 2},\
{'a': 1, 'b': 3}]
>>> results = order_by(items, ['a', 'b'])
>>> assert results == [{'a': 1, 'b': 3},\
{'a': 2, 'b': 1},\
{'a': 3, 'b': 2}]
>>> results = order_by(items, ['-a', 'b'])
>>> assert results == [{'a': 3, 'b': 2},\
{'a': 2, 'b': 1},\
{'a': 1, 'b': 3}]
>>> results = order_by(items, ['a', 'b'], [False, True])
>>> assert results == [{'a': 3, 'b': 2},\
{'a': 2, 'b': 1},\
{'a': 1, 'b': 3}]
.. versionadded:: 3.0.0
.. versionchanged:: 3.2.0
Added `orders` argument.
.. versionchanged:: 3.2.0
Added :func:`sort_by_order` as alias.
.. versionchanged:: 4.0.0
Renamed from ``order_by`` to ``order_by`` and removed alias
``sort_by_order``.
"""
if isinstance(collection, dict):
collection = collection.values()
# Maintain backwards compatibility.
if pyd.is_boolean(orders):
reverse = orders
orders = None
comparers = []
if orders:
for i, key in enumerate(keys):
if pyd.has(orders, i):
order = 1 if orders[i] else -1
else:
order = 1
comparers.append((pyd.property_(key), order))
else:
for key in keys:
if key.startswith("-"):
order = -1
key = key[1:]
else:
order = 1
comparers.append((pyd.property_(key), order))
def comparison(left, right):
# pylint: disable=useless-else-on-loop,missing-docstring
for func, mult in comparers:
result = cmp(func(left), func(right))
if result:
return mult * result
return 0
return sorted(collection, key=cmp_to_key(comparison), reverse=reverse)
@t.overload
def partition(
collection: t.Mapping[T, T2], predicate: t.Callable[[T2, T, t.Dict[T, T2]], t.Any]
) -> t.List[t.List[T2]]: ...
@t.overload
def partition(
collection: t.Mapping[T, T2], predicate: t.Callable[[T2, T], t.Any]
) -> t.List[t.List[T2]]: ...
@t.overload
def partition(
collection: t.Mapping[t.Any, T2], predicate: t.Callable[[T2], t.Any]
) -> t.List[t.List[T2]]: ...
@t.overload
def partition(
collection: t.Mapping[t.Any, T2], predicate: t.Union[IterateeObjT, None] = None
) -> t.List[t.List[T2]]: ...
@t.overload
def partition(
collection: t.Iterable[T], predicate: t.Callable[[T, int, t.List[T]], t.Any]
) -> t.List[t.List[T]]: ...
@t.overload
def partition(
collection: t.Iterable[T], predicate: t.Callable[[T, int], t.Any]
) -> t.List[t.List[T]]: ...
@t.overload
def partition(
collection: t.Iterable[T], predicate: t.Callable[[T], t.Any]
) -> t.List[t.List[T]]: ...
@t.overload
def partition(
collection: t.Iterable[T], predicate: t.Union[IterateeObjT, None] = None
) -> t.List[t.List[T]]: ...
[docs]
def partition(collection, predicate=None):
"""
Creates an array of elements split into two groups, the first of which contains elements the
`predicate` returns truthy for, while the second of which contains elements the `predicate`
returns falsey for. The `predicate` is invoked with three arguments: ``(value, index|key,
collection)``.
If a property name is provided for `predicate` the created :func:`pluck` style predicate returns
the property value of the given element.
If an object is provided for `predicate` the created :func:`.matches` style predicate returns
``True`` for elements that have the properties of the given object, else ``False``.
Args:
collection: Collection to iterate over.
predicate: Predicate applied per iteration.
Returns:
List of grouped elements.
Example:
>>> partition([1, 2, 3, 4], lambda x: x >= 3)
[[3, 4], [1, 2]]
.. versionadded:: 1.1.0
"""
trues = []
falses = []
for is_true, value, _, _ in iteriteratee(collection, predicate):
if is_true:
trues.append(value)
else:
falses.append(value)
return [trues, falses]
[docs]
def pluck(collection: t.Iterable[t.Any], path: PathT) -> t.List[t.Any]:
"""
Retrieves the value of a specified property from all elements in the collection.
Args:
collection: List of dicts.
path: Collection's path to pluck
Returns:
Plucked list.
Example:
>>> pluck([{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}], "a")
[1, 3, 5]
>>> pluck([[[0, 1]], [[2, 3]], [[4, 5]]], "0.1")
[1, 3, 5]
>>> pluck([{"a": {"b": 1}}, {"a": {"b": 2}}], "a.b")
[1, 2]
>>> pluck([{"a": {"b": [0, 1]}}, {"a": {"b": [2, 3]}}], "a.b.1")
[1, 3]
>>> pluck([{"a": {"b": [0, 1]}}, {"a": {"b": [2, 3]}}], ["a", "b", 1])
[1, 3]
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Function removed.
.. versionchanged:: 4.0.1
Made property access deep.
"""
return map_(collection, pyd.property_(path))
@t.overload
def reduce_(
collection: t.Mapping[T, T2],
iteratee: t.Callable[[T3, T2, T], T3],
accumulator: T3,
) -> T3: ...
@t.overload
def reduce_(
collection: t.Mapping[t.Any, T2],
iteratee: t.Callable[[T3, T2], T3],
accumulator: T3,
) -> T3: ...
@t.overload
def reduce_(
collection: t.Mapping[t.Any, t.Any],
iteratee: t.Callable[[T3], T3],
accumulator: T3,
) -> T3: ...
@t.overload
def reduce_(
collection: t.Mapping[T, T2],
iteratee: t.Callable[[T2, T2, T], T2],
accumulator: None = None,
) -> T2: ...
@t.overload
def reduce_(
collection: t.Mapping[t.Any, T2],
iteratee: t.Callable[[T2, T2], T2],
accumulator: None = None,
) -> T2: ...
@t.overload
def reduce_(
collection: t.Mapping[t.Any, t.Any],
iteratee: t.Callable[[T], T],
accumulator: None = None,
) -> T: ...
@t.overload
def reduce_(
collection: t.Iterable[T],
iteratee: t.Callable[[T2, T, int], T2],
accumulator: T2,
) -> T2: ...
@t.overload
def reduce_(
collection: t.Iterable[T],
iteratee: t.Callable[[T2, T], T2],
accumulator: T2,
) -> T2: ...
@t.overload
def reduce_(
collection: t.Iterable[t.Any],
iteratee: t.Callable[[T2], T2],
accumulator: T2,
) -> T2: ...
@t.overload
def reduce_(
collection: t.Iterable[T],
iteratee: t.Callable[[T, T, int], T],
accumulator: None = None,
) -> T: ...
@t.overload
def reduce_(
collection: t.Iterable[T],
iteratee: t.Callable[[T, T], T],
accumulator: None = None,
) -> T: ...
@t.overload
def reduce_(
collection: t.Iterable[t.Any],
iteratee: t.Callable[[T], T],
accumulator: None = None,
) -> T: ...
@t.overload
def reduce_(
collection: t.Iterable[T], iteratee: None = None, accumulator: t.Union[T, None] = None
) -> T: ...
[docs]
def reduce_(collection, iteratee=None, accumulator=None):
"""
Reduces a collection to a value which is the accumulated result of running each element in the
collection through the iteratee, where each successive iteratee execution consumes the return
value of the previous execution.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
accumulator: Initial value of aggregator. Default is to use the result of
the first iteration.
Returns:
Accumulator object containing results of reduction.
Example:
>>> reduce_([1, 2, 3, 4], lambda total, x: total * x)
24
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Removed aliases ``foldl`` and ``inject``.
"""
iterable = iterator(collection)
if accumulator is None:
try:
_, accumulator = next(iterable)
except StopIteration as exc:
raise TypeError("reduce_() of empty sequence with no initial value") from exc
result = accumulator
if iteratee is None:
iteratee = pyd.identity
argcount = 1
else:
argcount = getargcount(iteratee, maxargs=3)
for index, item in iterable:
result = callit(iteratee, result, item, index, argcount=argcount)
return result
@t.overload
def reduce_right(
collection: t.Mapping[T, T2],
iteratee: t.Callable[[T3, T2, T], T3],
accumulator: T3,
) -> T3: ...
@t.overload
def reduce_right(
collection: t.Mapping[t.Any, T2],
iteratee: t.Callable[[T3, T2], T3],
accumulator: T3,
) -> T3: ...
@t.overload
def reduce_right(
collection: t.Mapping[t.Any, t.Any],
iteratee: t.Callable[[T3], T3],
accumulator: T3,
) -> T3: ...
@t.overload
def reduce_right(
collection: t.Mapping[T, T2],
iteratee: t.Callable[[T2, T2, T], T2],
accumulator: None = None,
) -> T2: ...
@t.overload
def reduce_right(
collection: t.Mapping[t.Any, T2],
iteratee: t.Callable[[T2, T2], T2],
accumulator: None = None,
) -> T2: ...
@t.overload
def reduce_right(
collection: t.Mapping[t.Any, t.Any],
iteratee: t.Callable[[T], T],
accumulator: None = None,
) -> T: ...
@t.overload
def reduce_right(
collection: t.Iterable[T],
iteratee: t.Callable[[T2, T, int], T2],
accumulator: T2,
) -> T2: ...
@t.overload
def reduce_right(
collection: t.Iterable[T],
iteratee: t.Callable[[T2, T], T2],
accumulator: T2,
) -> T2: ...
@t.overload
def reduce_right(
collection: t.Iterable[t.Any],
iteratee: t.Callable[[T2], T2],
accumulator: T2,
) -> T2: ...
@t.overload
def reduce_right(
collection: t.Iterable[T],
iteratee: t.Callable[[T, T, int], T],
accumulator: None = None,
) -> T: ...
@t.overload
def reduce_right(
collection: t.Iterable[T],
iteratee: t.Callable[[T, T], T],
accumulator: None = None,
) -> T: ...
@t.overload
def reduce_right(
collection: t.Iterable[t.Any],
iteratee: t.Callable[[T], T],
accumulator: None = None,
) -> T: ...
@t.overload
def reduce_right(
collection: t.Iterable[T], iteratee: None = None, accumulator: t.Union[T, None] = None
) -> T: ...
[docs]
def reduce_right(collection, iteratee=None, accumulator=None):
"""
This method is like :func:`reduce_` except that it iterates over elements of a `collection` from
right to left.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
accumulator: Initial value of aggregator. Default is to use the result of
the first iteration.
Returns:
Accumulator object containing results of reduction.
Example:
>>> reduce_right([1, 2, 3, 4], lambda total, x: total**x)
4096
.. versionadded:: 1.0.0
.. versionchanged:: 3.2.1
Fix bug where collection was not reversed correctly.
.. versionchanged:: 4.0.0
Removed alias ``foldr``.
"""
if not isinstance(collection, dict):
collection = list(collection)[::-1]
return reduce_(collection, iteratee, accumulator)
@t.overload
def reductions(
collection: t.Mapping[T, T2],
iteratee: t.Callable[[T3, T2, T], T3],
accumulator: T3,
from_right: bool = False,
) -> t.List[T3]: ...
@t.overload
def reductions(
collection: t.Mapping[t.Any, T2],
iteratee: t.Callable[[T3, T2], T3],
accumulator: T3,
from_right: bool = False,
) -> t.List[T3]: ...
@t.overload
def reductions(
collection: t.Mapping[t.Any, t.Any],
iteratee: t.Callable[[T3], T3],
accumulator: T3,
from_right: bool = False,
) -> t.List[T3]: ...
@t.overload
def reductions(
collection: t.Mapping[T, T2],
iteratee: t.Callable[[T2, T2, T], T2],
accumulator: None = None,
from_right: bool = False,
) -> t.List[T2]: ...
@t.overload
def reductions(
collection: t.Mapping[t.Any, T2],
iteratee: t.Callable[[T2, T2], T2],
accumulator: None = None,
from_right: bool = False,
) -> t.List[T2]: ...
@t.overload
def reductions(
collection: t.Mapping[t.Any, t.Any],
iteratee: t.Callable[[T], T],
accumulator: None = None,
from_right: bool = False,
) -> t.List[T]: ...
@t.overload
def reductions(
collection: t.Iterable[T],
iteratee: t.Callable[[T2, T, int], T2],
accumulator: T2,
from_right: bool = False,
) -> t.List[T2]: ...
@t.overload
def reductions(
collection: t.Iterable[T],
iteratee: t.Callable[[T2, T], T2],
accumulator: T2,
from_right: bool = False,
) -> t.List[T2]: ...
@t.overload
def reductions(
collection: t.Iterable[t.Any],
iteratee: t.Callable[[T2], T2],
accumulator: T2,
from_right: bool = False,
) -> t.List[T2]: ...
@t.overload
def reductions(
collection: t.Iterable[T],
iteratee: t.Callable[[T, T, int], T],
accumulator: None = None,
from_right: bool = False,
) -> t.List[T]: ...
@t.overload
def reductions(
collection: t.Iterable[T],
iteratee: t.Callable[[T, T], T],
accumulator: None = None,
from_right: bool = False,
) -> t.List[T]: ...
@t.overload
def reductions(
collection: t.Iterable[t.Any],
iteratee: t.Callable[[T], T],
accumulator: None = None,
from_right: bool = False,
) -> t.List[T]: ...
@t.overload
def reductions(
collection: t.Iterable[T],
iteratee: None = None,
accumulator: t.Union[T, None] = None,
from_right: bool = False,
) -> t.List[T]: ...
[docs]
def reductions(collection, iteratee=None, accumulator=None, from_right=False):
"""
This function is like :func:`reduce_` except that it returns a list of every intermediate value
in the reduction operation.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
accumulator: Initial value of aggregator. Default is to use the result of
the first iteration.
Returns:
Results of each reduction operation.
Example:
>>> reductions([1, 2, 3, 4], lambda total, x: total * x)
[2, 6, 24]
Note:
The last element of the returned list would be the result of using
:func:`reduce_`.
.. versionadded:: 2.0.0
"""
if iteratee is None:
iteratee = pyd.identity
argcount = 1
else:
argcount = getargcount(iteratee, maxargs=3)
results = []
def interceptor(result, item, index):
result = callit(iteratee, result, item, index, argcount=argcount)
results.append(result)
return result
reducer = reduce_right if from_right else reduce_
reducer(collection, interceptor, accumulator)
return results
@t.overload
def reductions_right(
collection: t.Mapping[T, T2],
iteratee: t.Callable[[T3, T2, T], T3],
accumulator: T3,
) -> t.List[T3]: ...
@t.overload
def reductions_right(
collection: t.Mapping[t.Any, T2],
iteratee: t.Callable[[T3, T2], T3],
accumulator: T3,
) -> t.List[T3]: ...
@t.overload
def reductions_right(
collection: t.Mapping[t.Any, t.Any],
iteratee: t.Callable[[T3], T3],
accumulator: T3,
) -> t.List[T3]: ...
@t.overload
def reductions_right(
collection: t.Mapping[T, T2],
iteratee: t.Callable[[T2, T2, T], T2],
accumulator: None = None,
) -> t.List[T2]: ...
@t.overload
def reductions_right(
collection: t.Mapping[t.Any, T2],
iteratee: t.Callable[[T2, T2], T2],
accumulator: None = None,
) -> t.List[T2]: ...
@t.overload
def reductions_right(
collection: t.Mapping[t.Any, t.Any],
iteratee: t.Callable[[T], T],
accumulator: None = None,
) -> t.List[T]: ...
@t.overload
def reductions_right(
collection: t.Iterable[T],
iteratee: t.Callable[[T2, T, int], T2],
accumulator: T2,
) -> t.List[T2]: ...
@t.overload
def reductions_right(
collection: t.Iterable[T],
iteratee: t.Callable[[T2, T], T2],
accumulator: T2,
) -> t.List[T2]: ...
@t.overload
def reductions_right(
collection: t.Iterable[t.Any],
iteratee: t.Callable[[T2], T2],
accumulator: T2,
) -> t.List[T2]: ...
@t.overload
def reductions_right(
collection: t.Iterable[T],
iteratee: t.Callable[[T, T, int], T],
accumulator: None = None,
) -> t.List[T]: ...
@t.overload
def reductions_right(
collection: t.Iterable[T],
iteratee: t.Callable[[T, T], T],
accumulator: None = None,
) -> t.List[T]: ...
@t.overload
def reductions_right(
collection: t.Iterable[t.Any],
iteratee: t.Callable[[T], T],
accumulator: None = None,
) -> t.List[T]: ...
@t.overload
def reductions_right(
collection: t.Iterable[T], iteratee: None = None, accumulator: t.Union[T, None] = None
) -> t.List[T]: ...
[docs]
def reductions_right(collection, iteratee=None, accumulator=None):
"""
This method is like :func:`reductions` except that it iterates over elements of a `collection`
from right to left.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
accumulator: Initial value of aggregator. Default is to use the result of
the first iteration.
Returns:
Results of each reduction operation.
Example:
>>> reductions_right([1, 2, 3, 4], lambda total, x: total**x)
[64, 4096, 4096]
Note:
The last element of the returned list would be the result of using
:func:`reduce_`.
.. versionadded:: 2.0.0
"""
return reductions(collection, iteratee, accumulator, from_right=True)
@t.overload
def reject(
collection: t.Mapping[T, T2],
predicate: t.Union[t.Callable[[T2, T, t.Dict[T, T2]], t.Any], IterateeObjT, None] = None,
) -> t.List[T2]: ...
@t.overload
def reject(
collection: t.Mapping[T, T2],
predicate: t.Union[t.Callable[[T2, T], t.Any], IterateeObjT, None] = None,
) -> t.List[T2]: ...
@t.overload
def reject(
collection: t.Mapping[t.Any, T2],
predicate: t.Union[t.Callable[[T2], t.Any], IterateeObjT, None] = None,
) -> t.List[T2]: ...
@t.overload
def reject(
collection: t.Iterable[T],
predicate: t.Union[t.Callable[[T, int, t.List[T]], t.Any], IterateeObjT, None] = None,
) -> t.List[T]: ...
@t.overload
def reject(
collection: t.Iterable[T],
predicate: t.Union[t.Callable[[T, int], t.Any], IterateeObjT, None] = None,
) -> t.List[T]: ...
@t.overload
def reject(
collection: t.Iterable[T],
predicate: t.Union[t.Callable[[T], t.Any], IterateeObjT, None] = None,
) -> t.List[T]: ...
[docs]
def reject(collection, predicate=None):
"""
The opposite of :func:`filter_` this method returns the elements of a collection that the
predicate does **not** return truthy for.
Args:
collection: Collection to iterate over.
predicate: Predicate applied per iteration.
Returns:
Rejected elements of `collection`.
Example:
>>> reject([1, 2, 3, 4], lambda x: x >= 3)
[1, 2]
>>> reject([{"a": 0}, {"a": 1}, {"a": 2}], "a")
[{'a': 0}]
>>> reject([{"a": 0}, {"a": 1}, {"a": 2}], {"a": 1})
[{'a': 0}, {'a': 2}]
.. versionadded:: 1.0.0
"""
return [value for is_true, value, _, _ in iteriteratee(collection, predicate) if not is_true]
[docs]
def sample(collection: t.Sequence[T]) -> T:
"""
Retrieves a random element from a given `collection`.
Args:
collection: Collection to iterate over.
Returns:
Random element from the given collection.
Example:
>>> items = [1, 2, 3, 4, 5]
>>> results = sample(items)
>>> assert results in items
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Moved multiple samples functionality to :func:`sample_size`. This
function now only returns a single random sample.
"""
return random.choice(collection)
[docs]
def sample_size(collection: t.Sequence[T], n: t.Union[int, None] = None) -> t.List[T]:
"""
Retrieves list of `n` random elements from a collection.
Args:
collection: Collection to iterate over.
n: Number of random samples to return.
Returns:
List of `n` sampled collection values.
Examples:
>>> items = [1, 2, 3, 4, 5]
>>> results = sample_size(items, 2)
>>> assert len(results) == 2
>>> assert set(items).intersection(results) == set(results)
.. versionadded:: 4.0.0
"""
num = min(n or 1, len(collection))
return random.sample(collection, num)
@t.overload
def shuffle(collection: t.Mapping[t.Any, T]) -> t.List[T]: ...
@t.overload
def shuffle(collection: t.Iterable[T]) -> t.List[T]: ...
[docs]
def shuffle(collection):
"""
Creates a list of shuffled values, using a version of the Fisher-Yates shuffle.
Args:
collection: Collection to iterate over.
Returns:
Shuffled list of values.
Example:
>>> items = [1, 2, 3, 4]
>>> results = shuffle(items)
>>> assert len(results) == len(items)
>>> assert set(results) == set(items)
.. versionadded:: 1.0.0
"""
if isinstance(collection, dict):
collection = collection.values()
# Make copy of collection since random.shuffle works on list in-place.
collection = list(collection)
# NOTE: random.shuffle uses Fisher-Yates.
random.shuffle(collection)
return collection
[docs]
def size(collection: t.Sized) -> int:
"""
Gets the size of the `collection` by returning `len(collection)` for iterable objects.
Args:
collection: Collection to iterate over.
Returns:
Collection length.
Example:
>>> size([1, 2, 3, 4])
4
.. versionadded:: 1.0.0
"""
return len(collection)
[docs]
def some(
collection: t.Iterable[T], predicate: t.Union[t.Callable[[T], t.Any], None] = None
) -> bool:
"""
Checks if the predicate returns a truthy value for any element of a collection. The predicate is
invoked with three arguments: ``(value, index|key, collection)``. If a property name is passed
for predicate, the created :func:`map_` style predicate will return the property value of the
given element. If an object is passed for predicate, the created :func:`.matches` style
predicate will return ``True`` for elements that have the properties of the given object, else
``False``.
Args:
collection: Collection to iterate over.
predicate: Predicate applied per iteration.
Returns:
Whether any of the elements are truthy.
Example:
>>> some([False, True, 0])
True
>>> some([False, 0, None])
False
>>> some([1, 2, 3, 4], lambda x: x >= 3)
True
>>> some([1, 2, 3, 4], lambda x: x == 0)
False
.. versionadded:: 1.0.0
.. versionchanged:: 4.0.0
Removed alias ``any_``.
"""
if predicate:
cbk = pyd.iteratee(predicate)
collection = (cbk(item) for item in collection)
return any(collection)
@t.overload
def sort_by(
collection: t.Mapping[t.Any, T2],
iteratee: t.Union[t.Callable[[T2], t.Any], IterateeObjT, None] = None,
reverse: bool = False,
) -> t.List[T2]: ...
@t.overload
def sort_by(
collection: t.Iterable[T],
iteratee: t.Union[t.Callable[[T], t.Any], IterateeObjT, None] = None,
reverse: bool = False,
) -> t.List[T]: ...
[docs]
def sort_by(collection, iteratee=None, reverse=False):
"""
Creates a list of elements, sorted in ascending order by the results of running each element in
a `collection` through the iteratee.
Args:
collection: Collection to iterate over.
iteratee: Iteratee applied per iteration.
reverse: Whether to reverse the sort. Defaults to ``False``.
Returns:
Sorted list.
Example:
>>> sort_by({"a": 2, "b": 3, "c": 1})
[1, 2, 3]
>>> sort_by({"a": 2, "b": 3, "c": 1}, reverse=True)
[3, 2, 1]
>>> sort_by([{"a": 2}, {"a": 3}, {"a": 1}], "a")
[{'a': 1}, {'a': 2}, {'a': 3}]
.. versionadded:: 1.0.0
"""
if isinstance(collection, dict):
collection = collection.values()
return sorted(collection, key=pyd.iteratee(iteratee), reverse=reverse)
#
# Utility methods not a part of the main API
#
def itermap(
collection: t.Iterable[t.Any],
iteratee: t.Union[t.Callable[..., t.Any], IterateeObjT, None] = None,
) -> t.Generator[t.Any, None, None]:
"""Generative mapper."""
for result in iteriteratee(collection, iteratee):
yield result[0]