Skip to content

Commit

Permalink
Implemented Collection::countBy
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Dec 26, 2013
1 parent 55c5e04 commit 8d6ffa8
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 3 deletions.
26 changes: 26 additions & 0 deletions Cake/Test/TestCase/Utility/CollectionTest.php
Expand Up @@ -415,4 +415,30 @@ public function testIndexByDeep() {
$this->assertEquals($expected, iterator_to_array($grouped));
}

/**
* Tests countBy
*
* @return void
*/
public function testCountBy() {
$items = [
['id' => 1, 'name' => 'foo', 'parent_id' => 10],
['id' => 2, 'name' => 'bar', 'parent_id' => 11],
['id' => 3, 'name' => 'baz', 'parent_id' => 10],
];
$collection = new Collection($items);
$grouped = $collection->countBy('parent_id');
$expected = [
10 => 2,
11 => 1
];
$this->assertEquals($expected, iterator_to_array($grouped));
$this->assertInstanceOf('\Cake\Utility\Collection', $grouped);

$grouped = $collection->countBy(function($element) {
return $element['parent_id'];
});
$this->assertEquals($expected, iterator_to_array($grouped));
}

}
53 changes: 50 additions & 3 deletions Cake/Utility/Collection.php
Expand Up @@ -19,6 +19,7 @@
use Cake\Utility\Iterator\FilterIterator;
use Cake\Utility\Iterator\ReplaceIterator;
use Cake\Utility\Iterator\SortIterator;
use Cake\Utility\MapReduce;
use InvalidArgumentException;
use IteratorIterator;

Expand Down Expand Up @@ -395,7 +396,7 @@ public function sortBy($callback, $dir = SORT_DESC, $type = SORT_NUMERIC) {
* return $e['parent_id'];
* });
*
* //Result will look like
* //Result will look like this when converted to array
* [
* 10 => [
* ['id' => 1, 'name' => 'foo', 'parent_id' => 10],
Expand Down Expand Up @@ -445,7 +446,7 @@ public function groupBy($callback) {
* return $e['id'];
* });
*
* //Result will look like
* //Result will look like this when converted to array
* [
* 1 => ['id' => 1, 'name' => 'foo'],
* 3 => ['id' => 3, 'name' => 'baz'],
Expand All @@ -466,7 +467,53 @@ public function indexBy($callback) {
return new self($group);
}

public function countBy($property) {
/**
* Sorts a list into groups and returns a count for the number of elements
* in each group. Similar to groupBy, but instead of returning a list of values,
* returns a count for the number of values in that group.
*
* When $callback is a string it should be a property name to extract or
* a dot separated path of properties that should be followed to get the last
* one in the path.
*
* ###Example:
*
* {{{
* $items = [
* ['id' => 1, 'name' => 'foo', 'parent_id' => 10],
* ['id' => 2, 'name' => 'bar', 'parent_id' => 11],
* ['id' => 3, 'name' => 'baz', 'parent_id' => 10],
* ];
*
* $group = (new Collection($items))->countBy('parent_id');
*
* //Or
* $group = (new Collection($items))->countBy(function($e) {
* return $e['parent_id'];
* });
*
* //Result will look like this when converted to array
* [
* 10 => 2,
* 11 => 1
* ];
* }}}
*
* @param callable|string the callback or column name to use for indexing
* or a function returning the indexing key out of the provided element
* @return \Cake\Utility\Collection
*/
public function countBy($callback) {
$callback = $this->_propertyExtractor($callback);

$mapper = function($key, $value, $mr) use ($callback) {
$mr->emitIntermediate($callback($value), $value);
};

$reducer = function ($key, $values, $mr) {
$mr->emit(count($values), $key);
};
return new self(new MapReduce($this, $mapper, $reducer));
}

public function shuffle() {
Expand Down

0 comments on commit 8d6ffa8

Please sign in to comment.