Skip to content

Commit

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

/**
* Tests indexBy
*
* @return void
*/
public function testIndexBy() {
$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->indexBy('id');
$expected = [
1 => ['id' => 1, 'name' => 'foo', 'parent_id' => 10],
3 => ['id' => 3, 'name' => 'baz', 'parent_id' => 10],
2 => ['id' => 2, 'name' => 'bar', 'parent_id' => 11],
];
$this->assertEquals($expected, iterator_to_array($grouped));
$this->assertInstanceOf('\Cake\Utility\Collection', $grouped);

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

/**
* Tests indexBy with a deep property
*
* @return void
*/
public function testIndexByDeep() {
$items = [
['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]],
['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]],
['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]],
];
$collection = new Collection($items);
$grouped = $collection->indexBy('thing.parent_id');
$expected = [
10 => ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]],
11 => ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]],
];
$this->assertEquals($expected, iterator_to_array($grouped));
}

}
2 changes: 1 addition & 1 deletion Cake/Test/TestCase/Utility/MapReduceTest.php
Expand Up @@ -84,7 +84,7 @@ public function testEmitFinalInMapper() {
}

/**
* Tests that a reducer is required when there are intermediate resutls
* Tests that a reducer is required when there are intermediate results
*
* @expectedException \LogicException
* @return void
Expand Down
45 changes: 44 additions & 1 deletion Cake/Utility/Collection.php
Expand Up @@ -420,7 +420,50 @@ public function groupBy($callback) {
return new self($group);
}

public function indexBy($property) {
/**
* Given a list, and an callback function that returns a key for each element
* in the list (or a property name) returns an object with an index of each item.
* Just like groupBy, but for when you know your keys are unique.
*
* 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'],
* ['id' => 2, 'name' => 'bar'],
* ['id' => 3, 'name' => 'baz'],
* ];
*
* $indexed = (new Collection($items))->indexBy('id');
*
* //Or
* $indexed = (new Collection($items))->indexBy(function($e) {
* return $e['id'];
* });
*
* //Result will look like
* [
* 1 => ['id' => 1, 'name' => 'foo'],
* 3 => ['id' => 3, 'name' => 'baz'],
* 2 => ['id' => 2, 'name' => 'bar'],
* ];
* }}}
*
* @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 indexBy($callback) {
$callback = $this->_propertyExtractor($callback);
$group = [];
foreach ($this as $value) {
$group[$callback($value)] = $value;
}
return new self($group);
}

public function countBy($property) {
Expand Down

0 comments on commit 55c5e04

Please sign in to comment.