diff --git a/README.md b/README.md index d6508f2..d49001b 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ list the function signatures as an overview: Iterator take(int $num, iterable $iterable) Iterator drop(int $num, iterable $iterable) Iterator repeat(mixed $value, int $num = INF) + Iterator cycle(iterable $iterable, int $num = INF) Iterator keys(iterable $iterable) Iterator values(iterable $iterable) bool any(callable $predicate, iterable $iterable) diff --git a/src/iter.php b/src/iter.php index 86718d2..9f86dd8 100644 --- a/src/iter.php +++ b/src/iter.php @@ -326,6 +326,33 @@ function repeat($value, $num = INF) { } } +/** + * Takes an iterator and cycles through its elements a given number of times + * + * If working with a generator it is best to make it rewindable if the expected + * number of elements is large + * + * Examples: + * + * iter\cycle([1, 2, 3], 3) + * => iter(1, 2, 3, 1, 2, 3, 1, 2, 3) + * + * @param mixed $iterable The iterator to cycle + * @param $num The number of items to cycle + * + * @return \Iterator + */ +function cycle($iterable, $num = INF) { + if ($iterable instanceof \Generator) { + $iterable = toArray($iterable); + } + for ($i = 0; $i < $num; ++$i) { + foreach ($iterable as $key => $value) { + yield $key => $value; + } + } +} + /** * Returns the keys of an iterable. * diff --git a/src/iter.rewindable.php b/src/iter.rewindable.php index d375867..504e9da 100644 --- a/src/iter.rewindable.php +++ b/src/iter.rewindable.php @@ -62,6 +62,7 @@ function slice() { return new _RewindableGenerator('iter\slice', fun function take() { return new _RewindableGenerator('iter\take', func_get_args()); } function drop() { return new _RewindableGenerator('iter\drop', func_get_args()); } function repeat() { return new _RewindableGenerator('iter\repeat', func_get_args()); } + function cycle() { return new _RewindableGenerator('iter\cycle', func_get_args()); } function takeWhile() { return new _RewindableGenerator('iter\takeWhile', func_get_args()); } function dropWhile() { return new _RewindableGenerator('iter\dropWhile', func_get_args()); } function keys() { return new _RewindableGenerator('iter\keys', func_get_args()); } diff --git a/test/iterTest.php b/test/iterTest.php index b94983e..b127f55 100644 --- a/test/iterTest.php +++ b/test/iterTest.php @@ -210,10 +210,17 @@ public function testFlip() { toArrayWithKeys(flip(['a' => 1, 'b' => 2, 'c' => 3])) ); } + + public function testCycle() { + $this->assertSame( + [1, 2, 1, 2, 1, 2, 1, 2], + toArray(cycle(rewindable\range(1, 2), 4)) + ); + } } class _CountableTestDummy implements \Countable { public function count() { return 42; } -} \ No newline at end of file +}