From b296bb3fd65ef46a8b2ce09c9250923a991bbe85 Mon Sep 17 00:00:00 2001 From: Raffaello Pieri Date: Wed, 20 Apr 2016 13:16:29 +0100 Subject: [PATCH] add group_by and sum_by functions --- src/FnDispatcher.php | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/FnDispatcher.php b/src/FnDispatcher.php index 2b1eaa1..caf3ac0 100644 --- a/src/FnDispatcher.php +++ b/src/FnDispatcher.php @@ -152,6 +152,31 @@ private function fn_min_by(array $args) return $this->reduce('min_by:1', $args[0], ['any'], $fn); } + private function fn_group_by(array $args) + { + $this->validate('group_by', $args, [['array'], ['expression']]); + $expr = $this->wrapExpression('group_by:1', $args[1], ['number', 'string']); + $fn = function ($carry, $item) use ($expr) { + $key = $expr($item); + $carry[$key][] = $item; + return $carry; + }; + return $this->reduce('group_by:1', $args[0], ['any'], $fn, []); + } + + private function fn_sum_by(array $args) + { + $this->validate('sum_by', $args, [['array'], ['expression'], ['expression']]); + $groupExpr = $this->wrapExpression('sum_by:1', $args[1], ['number', 'string']); + $complementExpr = $this->wrapExpression('sum_by:1', $args[2], ['number', 'number']); + $fn = function ($carry, $item) use ($groupExpr, $complementExpr) { + $key = $groupExpr($item); + $carry[$key] = ($carry[$key] ?? 0) + $complementExpr($item); + return $carry; + }; + return $this->reduce('sum_by:1', $args[0], ['any'], $fn, []); + } + private function fn_reverse(array $args) { $this->validate('reverse', $args, [['array', 'string']]); @@ -351,14 +376,15 @@ private function validateSeq($from, array $types, $a, $b) /** * Reduces and validates an array of values to a single value using a fn. * - * @param string $from String of function:argument_position - * @param array $values Values to reduce. - * @param array $types Array of valid value types. - * @param callable $reduce Reduce function that accepts ($carry, $item). + * @param string $from String of function:argument_position + * @param array $values Values to reduce. + * @param array $types Array of valid value types. + * @param callable $reduce Reduce function that accepts ($carry, $item). + * @param mixed|null $initial Value to use in as initial result or in case the result is empty * * @return mixed */ - private function reduce($from, array $values, array $types, callable $reduce) + private function reduce($from, array $values, array $types, callable $reduce, $initial = null) { $i = -1; return array_reduce( @@ -368,7 +394,8 @@ function ($carry, $item) use ($from, $types, $reduce, &$i) { $this->validateSeq($from, $types, $carry, $item); } return $reduce($carry, $item, $i); - } + }, + $initial ); }