Created
August 1, 2013 15:57
-
-
Save dhrrgn/6132705 to your computer and use it in GitHub Desktop.
(WIP) Functions creating iterators for looping, based off the python itertools module.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Functions creating iterators for looping, based off the python itertools | |
* module. | |
* | |
* @author Dan Horrigan <dan@dhorrigan.com> | |
* @license MIT License | |
* @copyright 2013 Daniel Horrigan | |
*/ | |
namespace iter; | |
use InvalidArgumentException; | |
/** | |
* A Generator which iterators through all the elements of all the arguments | |
* in order until all items have been iterated over. | |
* | |
* Example: | |
* | |
* foreach (chain(str_split('ABC'), str_split('DEF')) as $c) { | |
* echo $c." "; | |
* } | |
* // Output: A B C D E F | |
* | |
* @return Iterator | |
*/ | |
function chain() | |
{ | |
foreach (func_get_args() as $v) { | |
if ( ! _is_traversable($v)) { | |
throw new InvalidArgumentException("Value '{$v}', must be traversable."); | |
} | |
foreach ($v as $elem) { | |
yield $elem; | |
} | |
} | |
} | |
/** | |
* A simple counter Generator. It will start at the given number and add `step` | |
* to it infinitely. | |
* | |
* @param integer $start The number to start at. | |
* @param integer $step The amount to increase by each iteration. | |
* @return Iterator | |
*/ | |
function counter($start = 0, $step = 1) | |
{ | |
$i = $start; | |
while (true) { | |
yield $i; | |
$i += $step; | |
} | |
} | |
/** | |
* A generator that infinetly cycles through the given values. You can send | |
* either an array of values, or send the values as arguments. | |
* | |
* @param mixed $values If an array and the only argument, it is iterated over. | |
* @return Iterator | |
*/ | |
function cycle($values) | |
{ | |
if (func_num_args() > 1 || ! _acts_as_array($values)) { | |
$values = func_get_args(); | |
} | |
$i = 0; | |
$len = count($values); | |
while (true) { | |
if ($i === $len) { | |
$i = 0; | |
} | |
yield $values[$i]; | |
$i++; | |
} | |
} | |
/** | |
* The same as the PHP `range()` function, except implemented with an iterator. | |
* | |
* @param integer $start First value of the sequence. | |
* @param integer $end The value to end the sequence at. | |
* @param integer $step Amount to increment with each iteration. | |
* @return Iterator | |
*/ | |
function xrange($start, $end, $step = 1) | |
{ | |
foreach (counter($start, $step) as $i) { | |
yield $i; | |
if ($i === $end) { | |
break; | |
} | |
} | |
} | |
/** | |
* Repeats the given item either infinitly or the given amount of times. | |
* | |
* @param mixed $item The item to repeat. | |
* @param integer $times The number of times to repeat (null for inf) | |
* @return Iterator | |
*/ | |
function repeat($item, $times = null) | |
{ | |
if (is_null($times)) { | |
while (true) { | |
yield $item; | |
} | |
} else { | |
for ($i = 0; $i < $times; $i++) { | |
yield $i; | |
} | |
} | |
} | |
/** | |
* Checks if the given value can be traversed using a foreach loop. | |
* | |
* @param mixed $value The value to check. | |
* @return boolean | |
*/ | |
function _is_traversable($value) | |
{ | |
return is_array($value) || is_a($value, 'Traversable'); | |
} | |
/** | |
* Checks if the given value can be accessed like an array. | |
* | |
* @param mixed $value The value to check | |
* @return boolean | |
*/ | |
function _acts_as_array($value) | |
{ | |
return is_array($value) || (is_a($value, 'ArrayAccess') && is_a($value, 'Countable')); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment