collector maintained by collector
comments powered by Disqus
Collector
A collection library, inspired by Laravel, Refactoring to Collections, this tweet and my own need/desire for it. Built using generators to preserve memory when dealing with large data sets.
This was put together in about 2 hours - unit tests ripped straight from Laravel - I'd like to implement as much of the Laravel Collection class as possible in due time.
Create a collection
Use the static helper method collect
to create the collection, valid arguments are any objects implementing
\Iterator
including generators, any callable which can resolve to a generator or an array.
//iterator
$collection = Collector::collect(new ArrayIterator([1, 2, 3]);
//callable generator
$collection = Collector::collect(function () {
yield 1;
yield 2;
yield 3;
});
//array
$collection = Collector::collect([1, 2, 3]);
You can also use the more explicit static constructors if you wish:
//iterator
$collection = Collector::fromIterator(new ArrayIterator([1, 2, 3]);
//callable generator
$collection = Collector::fromCallable(function () {
yield 1;
yield 2;
yield 3;
});
//array
$collection = Collector::fromArray([1, 2, 3]);
Operations
Map
use Collector\Collector;
$source = function () {
yield 1;
yield 2;
yield 3;
};
$collection = Collector::fromCallable($source)
->map(function ($item, $key) {
return $item * 2;
});
var_dump($collection->asArray());
array(3) {
[0] =>
int(2)
[1] =>
int(4)
[2] =>
int(6)
}
Filter
use Collector\Collector;
$source = function () {
yield 1;
yield 2;
yield 3;
};
$collection = Collector::fromCallable($source)
->filter(function ($item, $key) {
return $item >=2;
});
var_dump($collection->asArray());
array(2) {
[1] =>
int(2)
[2] =>
int(3)
}
Flat Map
use Collector\Collector;
$source = function () {
yield ['name' => 'Aloo Gobi', 'ingredients' => ['Cauliflower', 'Potato']];
yield ['name' => 'Jelfrezi', 'ingredients' => ['Chicken', 'Tomatoes', 'Chili']];
};
$collection = Collector::fromCallable($source)
->flatMap(function ($item, $key) {
return $item['ingredients'];
});
var_dump($collection->asArray());
array(5) {
[0] =>
string(11) "Cauliflower"
[1] =>
string(6) "Potato"
[2] =>
string(7) "Chicken"
[3] =>
string(8) "Tomatoes"
[4] =>
string(5) "Chili"
}
Each
use Collector\Collector;
$source = function () {
yield ['name' => 'Aloo Gobi', 'ingredients' => ['Cauliflower', 'Potato']];
yield ['name' => 'Jelfrezi', 'ingredients' => ['Chicken', 'Tomatoes', 'Chili']];
};
$collection = Collector::fromCallable($source)
->each(function ($item, $key) {
echo $item['name'] . "\n";
});
//Outputs:
Aloo Gobi
Jelfrezi
Collapse
use Collector\Collector;
$source = function () {
yield ['garlic', 'chili', 'ginger', 'coriander'];
yield ['onions', 'tomatoes'];
};
$collection = Collector::fromCallable($source)
->collapse();
var_dump($collection->asArray());
array(6) {
[0] =>
string(6) "garlic"
[1] =>
string(5) "chili"
[2] =>
string(6) "ginger"
[3] =>
string(9) "coriander"
[4] =>
string(6) "onions"
[5] =>
string(8) "tomatoes"
}
Flip
use Collector\Collector;
$source = function () {
yield 'Aydin';
yield 'Caroline';
};
$collection = Collector::fromCallable($source)
->flip();
var_dump($collection->asArray());
array(2) {
'Aydin' =>
int(0)
'Caroline' =>
int(1)
}
Key By
use Collector\Collector;
$source = function () {
yield ['name' => 'Vienna'];
yield ['name' => 'Lower Austria'];
yield ['name' => 'Styria'];
};
$collection = Collector::fromCallable($source)
->keyBy(function ($item, $key) {
return $item['name'];
});
var_dump($collection->asArray());
array(3) {
'Vienna' =>
array(1) {
'name' =>
string(6) "Vienna"
}
'Lower Austria' =>
array(1) {
'name' =>
string(13) "Lower Austria"
}
'Styria' =>
array(1) {
'name' =>
string(6) "Styria"
}
}
Values
use Collector\Collector;
$source = function () {
yield 5 => 'Vienna';
yield 1 => 'Lower Austria';
yield 9 => 'Styria';
};
$collection = Collector::fromCallable($source)
->values();
var_dump($collection->asArray());
array(3) {
[0] =>
string(6) "Vienna"
[1] =>
string(13) "Lower Austria"
[2] =>
string(6) "Styria"
}
Keys
use Collector\Collector;
$source = function () {
yield 5 => 'Vienna';
yield 1 => 'Lower Austria';
yield 9 => 'Styria';
};
$collection = Collector::fromCallable($source)
->keys();
var_dump($collection->asArray());
array(3) {
[0] => int(5)
[1] => int(1)
[2] => int(9)
}
Zip
use Collector\Collector;
$countries = function () {
yield 'Austria';
yield 'Kyrgyzstan';
yield 'Burkina Faso';
};
$continents = function () {
yield 'Europe';
yield 'Asia';
yield 'Africa';
};
$zipped = Collector::fromCallable($countries)
->zip(Collector::fromCallable($continents));
foreach ($zipped as $zipPart) {
var_dump($zipPart->asArray());
}
array(2) {
[0] =>
string(7) "Austria"
[1] =>
string(6) "Europe"
}
array(2) {
[0] =>
string(10) "Kyrgyzstan"
[1] =>
string(4) "Asia"
}
array(2) {
[0] =>
string(12) "Burkina Faso"
[1] =>
string(6) "Africa"
}
Unit tests
git clone git@github.com:AydinHassan/collector.git
cd collector
composer install
composer test
Benchmarks
There are some bench marks included showing performance and memory consumption metrics of the collection against native operations.
git clone git@github.com:AydinHassan/collector.git
cd collector
composer install
./vendor/bin/phpbench run benchmarks/LoopOneHundredThousandItems.php --report=default
./vendor/bin/phpbench run benchmarks/MapOneMillionItems.php --report=default
./vendor/bin/phpbench run benchmarks/FilterOneMillionItems.php --report=default