Source code for pydash.collections

"""Functions that operate on lists and dicts.

.. versionadded:: 1.0.0
"""

from __future__ import absolute_import

import random

import pydash as pyd

from .helpers import itercallback, iterator, call_callback, NoValue


__all__ = (
    'all_',
    'any_',
    'at',
    'collect',
    'contains',
    'count_by',
    'deep_pluck',
    'detect',
    'each',
    'each_right',
    'every',
    'filter_',
    'find',
    'find_last',
    'find_where',
    'foldl',
    'foldr',
    'for_each',
    'for_each_right',
    'group_by',
    'include',
    'index_by',
    'inject',
    'invoke',
    'map_',
    'mapiter',
    'max_',
    'min_',
    'partition',
    'pluck',
    'reduce_',
    'reduce_right',
    'reductions',
    'reductions_right',
    'reject',
    'sample',
    'select',
    'shuffle',
    'size',
    'some',
    'sort_by',
    'to_list',
    'where',
)


[docs]def at(collection, *indexes): # pylint: disable=invalid-name """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 (list|dict): Collection to iterate over. indexes (mixed): The indexes of `collection` to retrieve, specified as individual indexes or arrays of indexes. Returns: list: filtered list .. versionadded:: 1.0.0 """ indexes = pyd.flatten_deep(indexes) return [collection[i] for i in indexes]
[docs]def contains(collection, target, from_index=0): """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 (list|dict): Collection to iterate over. target (mixed): Target value to compare to. from_index (int, optional): Offset to start search from. Returns: bool: Whether `target` is in `collection`. See Also: - :func:`contains` (main definition) - :func:`include` (alias) .. versionadded:: 1.0.0 """ if isinstance(collection, dict): collection = collection.values() else: # only makes sense to do this if `collection` is not a dict collection = collection[from_index:] return target in collection
include = contains
[docs]def count_by(collection, callback=None): """Creates an object composed of keys generated from the results of running each element of `collection` through the callback. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: dict: Dict containing counts by key. .. versionadded:: 1.0.0 """ ret = {} for result in itercallback(collection, callback): ret.setdefault(result[0], 0) ret[result[0]] += 1 return ret
[docs]def deep_pluck(collection, path): """Like pluck but works with deep paths. Args: collection (list|dict): list of dicts path (str|list): collection's path to pluck Returns: list: plucked list .. versionadded:: 2.2.0 """ return map_(collection, pyd.deep_property(path))
[docs]def every(collection, callback=None): """Checks if the callback returns a truthy value for all elements of a collection. The callback is invoked with three arguments: ``(value, index|key, collection)``. If a property name is passed for callback, the created :func:`pluck` style callback will return the property value of the given element. If an object is passed for callback, the created :func:`where` style callback will return ``True`` for elements that have the properties of the given object, else ``False``. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: bool: Whether all elements are truthy. See Also: - :func:`every` (main definition) - :func:`all_` (alias) .. versionadded:: 1.0.0 """ if callback: cbk = pyd.iteratee(callback) collection = [cbk(item) for item in collection] return all(collection)
all_ = every
[docs]def filter_(collection, callback=None): """Iterates over elements of a collection, returning an list of all elements the callback returns truthy for. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: list: Filtered list. See Also: - :func:`select` (main definition) - :func:`filter_` (alias) .. versionadded:: 1.0.0 """ return [value for is_true, value, _, _ in itercallback(collection, callback) if is_true]
select = filter_
[docs]def find(collection, callback=None): """Iterates over elements of a collection, returning the first element that the callback returns truthy for. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: mixed: First element found or ``None``. See Also: - :func:`find` (main definition) - :func:`detect` (alias) - :func:`find_where` (alias) .. versionadded:: 1.0.0 """ search = (collection[key] for is_true, _, key, _ in itercallback(collection, callback) if is_true) return next(search, None)
detect = find find_where = find
[docs]def find_last(collection, callback=None): """This method is like :func:`find` except that it iterates over elements of a `collection` from right to left. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: mixed: Last element found or ``None``. .. versionadded:: 1.0.0 """ search = (collection[key] for is_true, _, key, _ in itercallback(collection, callback, reverse=True) if is_true) return next(search, None)
[docs]def for_each(collection, callback=None): """Iterates over elements of a collection, executing the callback for each element. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: list|dict: `collection` See Also: - :func:`for_each` (main definition) - :func:`each` (alias) .. versionadded:: 1.0.0 """ next((None for ret, _, _, _ in itercallback(collection, callback) if ret is False), None) return collection
each = for_each
[docs]def for_each_right(collection, callback): """This method is like :func:`for_each` except that it iterates over elements of a `collection` from right to left. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: list|dict: `collection` See Also: - :func:`for_each_right` (main definition) - :func:`each_right` (alias) .. versionadded:: 1.0.0 """ next((None for ret, _, _, _ in itercallback(collection, callback, reverse=True) if ret is False), None) return collection
each_right = for_each_right
[docs]def group_by(collection, callback=None): """Creates an object composed of keys generated from the results of running each element of a `collection` through the callback. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: dict: Results of grouping by `callback`. .. versionadded:: 1.0.0 """ ret = {} cbk = pyd.iteratee(callback) for value in collection: key = cbk(value) ret.setdefault(key, []) ret[key].append(value) return ret
[docs]def index_by(collection, callback=None): """Creates an object composed of keys generated from the results of running each element of the collection through the given callback. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: dict: Results of indexing by `callback`. .. versionadded:: 1.0.0 """ ret = {} cbk = pyd.iteratee(callback) for value in collection: ret[cbk(value)] = value return ret
[docs]def invoke(collection, method_name, *args, **kargs): """Invokes the method named by `method_name` on each element in the `collection` returning a list of the results of each invoked method. Args: collection (list|dict): Collection to iterate over. method_name (str): Name of method to invoke. args (optional): Arguments to pass to method call. kargs (optional): Keyword arguments to pass to method call. Returns: list: List of results of invoking method of each item. .. versionadded:: 1.0.0 """ lst = [] for item in collection: if callable(method_name): lst.append(method_name(item, *args, **kargs)) else: lst.append(getattr(item, method_name)(*args, **kargs)) return lst
[docs]def map_(collection, callback=None): """Creates an array of values by running each element in the collection through the callback. The callback is invoked with three arguments: ``(value, index|key, collection)``. If a property name is passed for callback, the created :func:`pluck` style callback will return the property value of the given element. If an object is passed for callback, the created :func:`where` style callback will return ``True`` for elements that have the properties of the given object, else ``False``. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: list: Mapped list. See Also: - :func:`map_` (main definition) - :func:`collect` (alias) .. versionadded:: 1.0.0 """ return list(mapiter(collection, callback))
collect = map_
[docs]def mapiter(collection, callback=None): """Like :func:`map_` except returns a generator. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: generator: Each mapped item. .. versionadded:: 2.1.0 """ for result in itercallback(collection, callback): yield result[0]
[docs]def max_(collection, callback=None): """Retrieves the maximum value of a `collection`. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: mixed: Maximum value. .. versionadded:: 1.0.0 """ if isinstance(collection, dict): collection = collection.values() return max(collection, key=pyd.iteratee(callback))
[docs]def min_(collection, callback=None): """Retrieves the minimum value of a `collection`. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: mixed: Minimum value. .. versionadded:: 1.0.0 """ if isinstance(collection, dict): collection = collection.values() return min(collection, key=pyd.iteratee(callback))
[docs]def partition(collection, callback=None): """Creates an array of elements split into two groups, the first of which contains elements the `callback` returns truthy for, while the second of which contains elements the `callback` returns falsey for. The `callback` is invoked with three arguments: ``(value, index|key, collection)``. If a property name is provided for `callback` the created :func:`pluck` style callback returns the property value of the given element. If an object is provided for `callback` the created :func:`where` style callback returns ``True`` for elements that have the properties of the given object, else ``False``. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: list: List of grouped elements. .. versionadded:: 1.1.0 """ trues = [] falses = [] for is_true, value, _, _ in itercallback(collection, callback): if is_true: trues.append(value) else: falses.append(value) return [trues, falses]
[docs]def pluck(collection, key): """Retrieves the value of a specified property from all elements in the collection. Args: collection (list|dict): list of dicts key (str): collection's key to pluck Returns: list: plucked list .. versionadded:: 1.0.0 """ return map_(collection, pyd.prop(key))
[docs]def reduce_(collection, callback=None, accumulator=None): """Reduces a collection to a value which is the accumulated result of running each element in the collection through the callback, where each successive callback execution consumes the return value of the previous execution. Args: collection (list|dict): Collection to iterate over. callback (mixed): Callback applied per iteration. accumulator (mixed, optional): Initial value of aggregator. Default is to use the result of the first iteration. Returns: mixed: Accumulator object containing results of reduction. See Also: - :func:`reduce_` (main definition) - :func:`foldl` (alias) - :func:`inject` (alias) .. versionadded:: 1.0.0 """ iterable = iterator(collection) if accumulator is None: try: _, accumulator = next(iterable) except StopIteration: raise TypeError( 'reduce_() of empty sequence with no initial value') result = accumulator if callback is None: callback = lambda item, *args: item for index, item in iterable: result = call_callback(callback, result, item, index) return result
foldl = reduce_ inject = reduce_
[docs]def reduce_right(collection, callback=None, accumulator=None): """This method is like :func:`reduce_` except that it iterates over elements of a `collection` from right to left. Args: collection (list|dict): Collection to iterate over. callback (mixed): Callback applied per iteration. accumulator (mixed, optional): Initial value of aggregator. Default is to use the result of the first iteration. Returns: mixed: Accumulator object containing results of reduction. See Also: - :func:`reduce_right` (main definition) - :func:`foldr` (alias) .. versionadded:: 1.0.0 """ if not isinstance(collection, dict): collection = sorted(collection, reverse=True) return reduce_(collection, callback, accumulator)
foldr = reduce_right
[docs]def reductions(collection, callback=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 (list|dict): Collection to iterate over. callback (mixed): Callback applied per iteration. accumulator (mixed, optional): Initial value of aggregator. Default is to use the result of the first iteration. Returns: list: Results of each reduction operation. Note: The last element of the returned list would be the result of using :func:`reduce_`. .. versionadded:: 2.0.0 """ if callback is None: callback = lambda item, *args: item results = [] def interceptor(result, item, index): # pylint: disable=missing-docstring result = call_callback(callback, result, item, index) results.append(result) return result reducer = reduce_right if from_right else reduce_ reducer(collection, interceptor, accumulator) return results
[docs]def reductions_right(collection, callback=None, accumulator=None): """This method is like :func:`reductions` except that it iterates over elements of a `collection` from right to left. Args: collection (list|dict): Collection to iterate over. callback (mixed): Callback applied per iteration. accumulator (mixed, optional): Initial value of aggregator. Default is to use the result of the first iteration. Returns: list: Results of each reduction operation. Note: The last element of the returned list would be the result of using :func:`reduce_`. .. versionadded:: 2.0.0 """ return reductions(collection, callback, accumulator, from_right=True)
[docs]def reject(collection, callback=None): """The opposite of :func:`filter_` this method returns the elements of a collection that the callback does **not** return truthy for. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: list: Rejected elements of `collection`. .. versionadded:: 1.0.0 """ return [value for is_true, value, _, _ in itercallback(collection, callback) if not is_true]
[docs]def sample(collection, n=None): """Retrieves a random element or `n` random elements from a `collection`. Args: collection (list|dict): Collection to iterate over. n (int, optional): Number of random samples to return. Returns: list|mixed: List of sampled collection value if `n` is provided, else single value from collection if `n` is ``None``. .. versionadded:: 1.0.0 """ num = min(n or 1, len(collection)) sampled = random.sample(collection, num) return sampled[0] if n is None else sampled
[docs]def shuffle(collection): """Creates a list of shuffled values, using a version of the Fisher-Yates shuffle. Args: collection (list|dict): Collection to iterate over. Returns: list: Shuffled list of values. .. 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): """Gets the size of the `collection` by returning `len(collection)` for iterable objects. Args: collection (list|dict): Collection to iterate over. Returns: int: Collection length. .. versionadded:: 1.0.0 """ return len(collection)
[docs]def some(collection, callback=None): """Checks if the callback returns a truthy value for any element of a collection. The callback is invoked with three arguments: ``(value, index|key, collection)``. If a property name is passed for callback, the created :func:`pluck` style callback will return the property value of the given element. If an object is passed for callback, the created :func:`where` style callback will return ``True`` for elements that have the properties of the given object, else ``False``. Args: collection (list|dict): Collection to iterate over. callbacked (mixed, optional): Callback applied per iteration. Returns: bool: Whether any of the elements are truthy. See Also: - :func:`some` (main definition) - :func:`any_` (alias) .. versionadded:: 1.0.0 """ if callback: cbk = pyd.iteratee(callback) collection = [cbk(item) for item in collection] return any(collection)
any_ = some
[docs]def sort_by(collection, callback=None): """Creates a list of elements, sorted in ascending order by the results of running each element in a `collection` through the callback. Args: collection (list|dict): Collection to iterate over. callback (mixed, optional): Callback applied per iteration. Returns: list: Sorted list. .. versionadded:: 1.0.0 """ if isinstance(collection, dict): collection = collection.values() return sorted(collection, key=pyd.iteratee(callback))
[docs]def to_list(collection): """Converts the collection to a list. Args: collection (list|dict): Collection to iterate over. Returns: list: Collection converted to list. .. versionadded:: 1.0.0 """ if isinstance(collection, dict): ret = collection.values() else: ret = list(collection) return ret
[docs]def where(collection, properties): """Examines each element in a collection, returning an array of all elements that have the given properties. Args: collection (list|dict): Collection to iterate over. properties (dict): property values to filter by Returns: list: filtered list. .. versionadded:: 1.0.0 """ return filter_(collection, pyd.matches(properties))