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