Skip to content

Commit a476583

Browse files
committed
added Iterables::repeatable()
1 parent 505a30a commit a476583

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

src/Utils/Iterables.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,31 @@ public static function mapWithKeys(iterable $iterable, callable $transformer): \
178178
}
179179

180180

181+
/**
182+
* Creates a repeatable iterator from a factory function.
183+
* The factory is called every time the iterator is iterated.
184+
* @template K
185+
* @template V
186+
* @param callable(): iterable<K, V> $factory
187+
* @return \IteratorAggregate<K, V>
188+
*/
189+
public static function repeatable(callable $factory): \IteratorAggregate
190+
{
191+
return new class ($factory) implements \IteratorAggregate {
192+
public function __construct(
193+
private $factory,
194+
) {
195+
}
196+
197+
198+
public function getIterator(): \Iterator
199+
{
200+
return Iterables::toIterator(($this->factory)());
201+
}
202+
};
203+
}
204+
205+
181206
/**
182207
* Wraps around iterator and caches its keys and values during iteration.
183208
* This allows the data to be re-iterated multiple times.
@@ -186,7 +211,7 @@ public static function mapWithKeys(iterable $iterable, callable $transformer): \
186211
* @param iterable<K, V> $iterable
187212
* @return \IteratorAggregate<K, V>
188213
*/
189-
public static function memoize(iterable $iterable): iterable
214+
public static function memoize(iterable $iterable): \IteratorAggregate
190215
{
191216
return new class (self::toIterator($iterable)) implements \IteratorAggregate {
192217
public function __construct(
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/**
4+
* Test: Nette\Utils\Iterables::repeatable()
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Nette\Utils\Iterables;
10+
use Tester\Assert;
11+
12+
require __DIR__ . '/../bootstrap.php';
13+
14+
15+
$counter = 0;
16+
$repeatable = Iterables::repeatable(function () use (&$counter) {
17+
$counter++;
18+
yield 'a' => 1;
19+
yield 'b' => 2;
20+
yield 'c' => 3;
21+
});
22+
23+
// First iteration
24+
Assert::same(
25+
['a' => 1, 'b' => 2, 'c' => 3],
26+
iterator_to_array($repeatable),
27+
);
28+
Assert::same(1, $counter);
29+
30+
// Second iteration - factory should be called again
31+
Assert::same(
32+
['a' => 1, 'b' => 2, 'c' => 3],
33+
iterator_to_array($repeatable),
34+
);
35+
Assert::same(2, $counter);
36+
37+
38+
// Test with empty iterator
39+
$repeatable = Iterables::repeatable(fn() => new EmptyIterator);
40+
Assert::same(
41+
[],
42+
iterator_to_array($repeatable),
43+
);

0 commit comments

Comments
 (0)