Skip to content

Instantly share code, notes, and snippets.

@georgepsarakis
Created December 15, 2013 17:18

Revisions

  1. georgepsarakis created this gist Dec 15, 2013.
    136 changes: 136 additions & 0 deletions itertools.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,136 @@
    <?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)));