Skip to content

Instantly share code, notes, and snippets.

@georgepsarakis
Created December 15, 2013 17:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save georgepsarakis/7975533 to your computer and use it in GitHub Desktop.
Save georgepsarakis/7975533 to your computer and use it in GitHub Desktop.
Map, filter with generator for numerically-indexed and associative arrays. Inspired from Python itertools - http://docs.python.org/2/library/itertools.html.
<?php
class Generator implements Iterator {
private $index = 0;
private $array = array();
private $keys = array();
private $filter = NULL;
private $mapper = NULL;
private $size = 0;
private $seek = 0;
private $last = NULL;
public function __construct(&$array) {
$this->index = 0;
// Keep only reference of the array
$this->array = &$array;
/*
We need a copy of the keys in order for our
code to work for associative arrays as well.
*/
$this->keys = array_keys($array);
$this->size = sizeof($this->keys);
}
function rewind() {
$this->index = 0;
}
public function get_size(){
return $this->size;
}
private function fetch(){
$value = $this->array[$this->keys[$this->seek]];
if ( !is_null($this->mapper) )
$value = call_user_func($this->mapper, $value);
if ( !is_null($this->filter) ) {
while ( !call_user_func($this->filter, $value) ){
$this->seek++;
if ( $this->seek < $this->size )
$value = $this->array[$this->keys[$this->seek]];
else
break;
}
$this->index = $this->seek;
}
$this->last = $value;
return $this->index < $this->size;
}
function current() {
return $this->last;
}
function key() {
if ( $this->valid() )
return $this->keys[$this->index];
}
function next() {
++$this->index;
$this->seek = $this->index;
}
function valid() {
return ($this->index < $this->size) && $this->fetch();
}
public function filter($callable){
$this->filter = $callable;
}
public function map($callable) {
$this->mapper = $callable;
}
}
function ifilter($function, &$iterable) {
$iterator = new Generator($iterable);
$iterator->filter($function);
return $iterator;
}
function ifilterfalse($function, &$iterable) {
return ifilter(function($item) use($function) { return !call_user_func($function, $item);}, $iterable);
}
function imap($function, &$iterable) {
$iterator = new Generator($iterable);
$iterator->map($function);
return $iterator;
}
/* No generator implementation for now but quite convenient! */
function zip(){
$arrays = func_get_args();
$loop = TRUE;
$minimum = min(array_map('sizeof', $arrays));
$zipped = array();
$counter = 0;
$values = array();
$array_loop = range(0, func_num_args()-1);
while ( $counter < $minimum ){
$values = array();
if ( $counter == 0 ){
foreach($array_loop as $index)
$values[] = current($arrays[$index]);
} else {
foreach($array_loop as $index)
$values[] = next($arrays[$index]);
}
$zipped[] = $values;
$counter++;
}
return $zipped;
}
/************/
/* Examples */
/************/
$a = range(1, 20);
print "-- ifilter\n";
foreach(ifilter(function($n){ return $n % 3 == 0; }, $a) as $key => $value){
print sprintf("%2d -> %s", $key, $value);
print "\n";
}
print "-- ifilterfalse\n";
foreach(ifilterfalse(function($n){ return $n % 3 == 0; }, $a) as $key => $value){
print sprintf("%2d -> %s", $key, $value);
print "\n";
}
print "-- imap\n";
foreach(imap(function($n){ return $n * $n; }, $a) as $key => $value){
print sprintf("%2d -> %s", $key, $value);
print "\n";
}
var_dump(zip(range(1,20), range(3,22), range(5,24)));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment