Skip to content

Commit

Permalink
Implemented Collection::combine()
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Jan 19, 2014
1 parent b2e093a commit 4de65e7
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 0 deletions.
74 changes: 74 additions & 0 deletions src/Collection/CollectionTrait.php
Expand Up @@ -627,6 +627,80 @@ public function append($items) {
return new Collection($list);
}

/**
* Returrns a new collection where the values extracted based on a value path
* and then indexed by a key path. Optionally this method can produce parent
* groups absed on a group property path.
*
* ### Examples:
*
* {{{
* $items = [
* ['id' => 1, 'name' => 'foo', 'parent' => 'a'],
* ['id' => 2, 'name' => 'bar', 'parent' => 'b'],
* ['id' => 3, 'name' => 'baz', 'parent' => 'a'],
* ];
*
* $combined = (new Collection($items))->combine('id', 'name');
*
* //Result will look like this when converted to array
* [
* 1 => 'foo',
* 2 => 'bar',
* 3 => 'baz,
* ];
*
* $combined = (new Collection($items))->combine('id', 'name', 'parent');
*
* //Result will look like this when converted to array
* [
* 'a' => [1 => 'foo', 3 => 'baz'],
* 'b' => [2 => 'bar']
* ];
* }}}
*
* @param callable|string $keyPath the column name path to use for indexing
* or a function returning the indexing key out of the provided element
* @param callable|string $valuePath the column name path to use as the array value
* or a function returning the value out of the provided element
* @param callable|string $valuePath the column name path to use as the parent
* grouping key or a function returning the key out of the provided element
* @return \Cake\Collection\Collection
*/
public function combine($keyPath, $valuePath, $groupPath = null) {
$options = [
'keyPath' => $this->_propertyExtractor($keyPath),
'valuePath' => $this->_propertyExtractor($valuePath),
'groupPath' => $groupPath ? $this->_propertyExtractor($groupPath) : null
];

$mapper = function($value, $key, $mapReduce) use ($options) {
$rowKey = $options['keyPath'];
$rowVal = $options['valuePath'];

if (!($options['groupPath'])) {
$mapReduce->emit($rowVal($value, $key), $rowKey($value, $key));
return;
}

$key = $options['groupPath']($value, $key);
$mapReduce->emitIntermediate(
[$rowKey($value, $key) => $rowVal($value, $key)],
$key
);
};

$reducer = function($values, $key, $mapReduce) {
$result = [];
foreach ($values as $value) {
$result += $value;
}
$mapReduce->emit($result, $key);
};

return new Collection(new MapReduce($this, $mapper, $reducer));
}

/**
* Returns an array representation of the results
*
Expand Down
45 changes: 45 additions & 0 deletions tests/TestCase/Collection/CollectionTest.php
Expand Up @@ -631,4 +631,49 @@ public function testCompile() {
$this->assertEquals(['a' => 4, 'b' => 5, 'c' => 6], $compiled->toArray());
}

/**
* Tests the combine method
*
* @return void
*/
public function testCombine() {
$items = [
['id' => 1, 'name' => 'foo', 'parent' => 'a'],
['id' => 2, 'name' => 'bar', 'parent' => 'b'],
['id' => 3, 'name' => 'baz', 'parent' => 'a']
];
$collection = (new Collection($items))->combine('id', 'name');
$expected = [1 => 'foo', 2 => 'bar', 3 => 'baz'];
$this->assertEquals($expected, $collection->toArray());

$expected = ['foo' => 1, 'bar' => 2, 'baz' => 3];
$collection = (new Collection($items))->combine('name', 'id');
$this->assertEquals($expected, $collection->toArray());

$collection = (new Collection($items))->combine('id', 'name', 'parent');
$expected = ['a' => [1 => 'foo', 3 => 'baz'], 'b' => [2 => 'bar']];
$this->assertEquals($expected, $collection->toArray());

$expected = [
'0-1' => ['foo-0-1' => '0-1-foo'],
'1-2' => ['bar-1-2' => '1-2-bar'],
'2-3' => ['baz-2-3' => '2-3-baz']
];
$collection = (new Collection($items))->combine(
function($value, $key) {
return $value['name'] . '-' . $key;
},
function($value, $key) {
return $key . '-' . $value['name'];
},
function($value, $key) {
return $key . '-' . $value['id'];
}
);
$this->assertEquals($expected, $collection->toArray());

$collection = (new Collection($items))->combine('id', 'crazy');
$this->assertEquals([1 => null, 2 => null, 3 => null], $collection->toArray());
}

}

0 comments on commit 4de65e7

Please sign in to comment.