/** * Memoizes callbacks and returns there value instead of calling them * * @param callable $callback Callable closure or function * @param array $arguments Arguments * @param array|string $key Optional memoize key to override the auto calculated hash * @return mixed */ function memoize($callback, array $arguments = array(), $key = null) { Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 1); static $keyGenerator = null, $storage = array(); if (!$keyGenerator) { $keyGenerator = function ($value) use(&$keyGenerator) { $type = gettype($value); if ($type === 'array') { $key = join(':', map($value, $keyGenerator)); } elseif ($type === 'object') { $key = get_class($value) . ':' . spl_object_hash($value); } else { $key = (string) $value; } return $key; }; } if ($key === null) { $key = $keyGenerator(array_merge(array($callback), $arguments)); } else { $key = $keyGenerator($key); } if (!isset($storage[$key]) && !array_key_exists($key, $storage)) { $storage[$key] = call_user_func_array($callback, $arguments); } return $storage[$key]; }
/** * Alias for Functional\first * * @param Traversable|array $collection * @param callable $callback * @return mixed */ function head($collection, $callback = null) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); if ($callback !== null) { Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); } return first($collection, $callback); }
/** * Iterates over a collection of elements, yielding each in turn to a callback function. Each invocation of $callback * is called with three arguments: (element, index, collection) * * @param Traversable|array $collection * @param callable $callback * @return null */ function each($collection, $callback) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); foreach ($collection as $index => $element) { call_user_func($callback, $element, $index, $collection); } }
/** * @param Traversable|array $collection * @param callable $callback * @return array */ function reduce_left($collection, $callback, $initial = null) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); foreach ($collection as $index => $value) { $initial = call_user_func($callback, $value, $index, $collection, $initial); } return $initial; }
/** * Produces a new array of elements by mapping each element in collection through a transformation function (callback). * Callback arguments will be element, index, collection * * @param Traversable|array $collection * @param callable $callback * @return array */ function map($collection, $callback) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); $aggregation = array(); foreach ($collection as $index => $element) { $aggregation[$index] = call_user_func($callback, $element, $index, $collection); } return $aggregation; }
/** * Returns true if all of the elements in the collection pass the callback falsy test. Opposite of Functional\all(). * Callback arguments will be element, index, collection. * * @param Traversable|array $collection * @param callable $callback * @return bool */ function none($collection, $callback) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); foreach ($collection as $index => $element) { if (call_user_func($callback, $element, $index, $collection)) { return false; } } return true; }
/** * Partitions a collection by callback result. The thruthy partition is the first one * (array index "0"), the falsy the second one (array index "1") * * @param Traversable|array $collection * @param callable $callback * @return array */ function partition($collection, $callback) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); $partitions = array(0 => array(), 1 => array()); foreach ($collection as $index => $element) { $partitionKey = call_user_func($callback, $element, $index, $collection) ? 0 : 1; $partitions[$partitionKey][$index] = $element; } return $partitions; }
/** * @param Traversable|array $collection * @param callable $callback * @return array */ function reduce_right($collection, $callback, $initial = null) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); $data = array(); foreach ($collection as $index => $value) { $data[] = array($index, $value); } while (list($index, $value) = array_pop($data)) { $initial = call_user_func($callback, $value, $index, $collection, $initial); } return $initial; }
/** * Drop all elements from a collection after callback returns true * * @param Traversable|array $collection * @param callable|integer $callback * @return array */ function drop_last($collection, $callback) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); $result = array(); $drop = false; foreach ($collection as $index => $element) { if (!$drop && !call_user_func($callback, $element, $index, $collection)) { break; } $result[$index] = $element; } return $result; }
/** * Looks through each element in the collection, returning the last one that passes a truthy test (callback). * Callback arguments will be element, index, collection * * @param Traversable|array $collection * @param callable $callback * @return mixed */ function last($collection, $callback = null) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); if ($callback !== null) { Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); } $match = null; foreach ($collection as $index => $element) { if ($callback === null || call_user_func($callback, $element, $index, $collection)) { $match = $element; } } return $match; }
/** * Looks through each element in the collection, returning the first one that passes a truthy test (callback). The * function returns as soon as it finds an acceptable element, and doesn't traverse the entire collection. Callback * arguments will be element, index, collection * * @param Traversable|array $collection * @param callable $callback * @return mixed */ function first($collection, $callback = null) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); if ($callback !== null) { Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); } foreach ($collection as $index => $element) { if ($callback === null) { return $element; } if (call_user_func($callback, $element, $index, $collection)) { return $element; } } }
/** * Groups a collection by index returned by callback. * * @param Traversable|array $collection * @param callable $callback * @return array */ function group($collection, $callback) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); $groups = array(); foreach ($collection as $index => $element) { $groupKey = call_user_func($callback, $element, $index, $collection); Exceptions\InvalidArgumentException::assertValidArrayKey($groupKey, __FUNCTION__); if (!isset($groups[$groupKey])) { $groups[$groupKey] = array(); } $groups[$groupKey][$index] = $element; } return $groups; }
/** * Drop all elements from a collection until callback returns false * * @param Traversable|array $collection * @param callable $callback * @return array */ function drop_first($collection, $callback) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); $result = array(); $drop = true; foreach ($collection as $index => $element) { if ($drop) { if (!call_user_func($callback, $element, $index, $collection)) { $drop = false; } else { continue; } } $result[$index] = $element; } return $result; }
/** * Returns all items from $collection except first element (head). Preserves $collection keys. * Takes an optional callback for filtering the collection. * * @param Traversable|array $ * @param callable $callback * @return array */ function tail($collection, $callback = null) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); if ($callback !== null) { Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); } $tail = array(); $isHead = true; foreach ($collection as $index => $element) { if ($isHead) { $isHead = false; continue; } if (!$callback || call_user_func($callback, $element, $index, $collection)) { $tail[$index] = $element; } } return $tail; }
/** * Returns a array of unique elements * * @param Traversable|array $collection * @param callable $callback * @return array */ function unique($collection, $callback = null, $strict = true) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); if ($callback != null) { Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); } $indexes = array(); $aggregation = array(); foreach ($collection as $key => $element) { if ($callback) { $index = call_user_func($callback, $element, $key, $collection); } else { $index = $element; } if (!in_array($index, $indexes, $strict)) { $aggregation[$key] = $element; $indexes[] = $index; } } return $aggregation; }
/** * Alias of Functional\select() * * @param Traversable|array $collection * @param callable $callback * @return array */ function filter($collection, $callback) { Exceptions\InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); Exceptions\InvalidArgumentException::assertCallback($callback, __FUNCTION__, 2); return select($collection, $callback); }