Skip to content

Instantly share code, notes, and snippets.

@jm42
Created October 26, 2014 20:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save jm42/cb328106f393eeb28751 to your computer and use it in GitHub Desktop.
Save jm42/cb328106f393eeb28751 to your computer and use it in GitHub Desktop.
PHP `itertools.groupby` implementation
<?php
class GroupIterator implements Iterator
{
protected $keyfunc;
protected $iter;
protected $key = null;
protected $value = null;
protected $group = null;
public function __construct(Iterator $iterator, Closure $key = null) {
if ($key === null) {
$key = function($k) {
return $k;
};
}
$this->keyfunc = $key;
$this->iter = $iterator;
}
protected function grouper($group) {
while ($group === $this->key) {
yield $this->value;
next($this->iter);
$this->value = current($this->iter);
$this->key = call_user_func($this->keyfunc, $this->value);
}
}
public function current() {
return $this->grouper($this->group);
}
public function next() {
while ($this->group === $this->key) {
next($this->iter);
$this->value = current($this->iter);
$this->key = call_user_func($this->keyfunc, $this->value);
}
$this->group = $this->key;
}
public function key() {
return $this->group;
}
public function valid() {
return key($this->iter) !== null;
}
public function rewind() {
reset($this->iter);
$this->value = current($this->iter);
$this->group = $this->key = call_user_func($this->keyfunc, $this->value);
}
}
<?php
class GroupIteratorAggregate implements \IteratorAggregate
{
protected $keyfunc;
protected $iter;
public function __construct(Iterator $iterator, Closure $key = null) {
if ($key === null) {
$key = function($k) {
return $k;
};
}
$this->keyfunc = $key;
$this->iter = $iterator;
}
public function getIterator()
{
$array = array();
foreach ($this->iter as $value) {
$group = call_user_func($this->keyfunc, $value);
$array[$group] = $this->grouper($group, $value);
}
return new \ArrayIterator($array);
}
protected function grouper($group, $value) {
do {
yield $value;
next($this->iter);
$value = current($this->iter);
$key = call_user_func($this->keyfunc, $value);
} while ($key === $group);
}
}
<?php
// @see https://docs.python.org/2/library/itertools.html#itertools.groupby
include 'GroupIterator.php';
include 'GroupIteratorAggregate.php';
function iterator_to_array_deep(\Traversable $iterator, $use_keys = true) {
$array = array();
foreach ($iterator as $key => $value) {
if ($value instanceof \Iterator) {
$value = iterator_to_array_deep($value, $use_keys);
}
if ($use_keys) {
$array[$key] = $value;
} else {
$array[] = $value;
}
}
return $array;
}
class GroupIteratorTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider provide
*/
public function test($string, array $expected)
{
$array = new ArrayIterator(str_split($string));
$group = new GroupIterator($array);
$this->assertEquals($expected, iterator_to_array_deep($group));
}
/**
* @dataProvider provide
*/
public function testAggregate($string, array $expected)
{
$array = new ArrayIterator(str_split($string));
$group = new GroupIteratorAggregate($array);
$this->assertEquals($expected, iterator_to_array_deep($group));
}
public function provide()
{
return array(
array('A', array('A' => array('A'))),
array('AA', array('A' => array('A', 'A'))),
array('AAB', array('A' => array('A', 'A'), 'B' => array('B'))),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment