Skip to content

Commit

Permalink
feat: Add MapIterableAggregate and FilterIterableAggregate.
Browse files Browse the repository at this point in the history
  • Loading branch information
drupol committed Jun 15, 2022
1 parent eef38bc commit 6ea3e45
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 0 deletions.
35 changes: 35 additions & 0 deletions README.md
Expand Up @@ -21,9 +21,11 @@ The missing PHP iterators.
* `ClosureIterator`: `ClosureIterator(callable $callable, array $arguments = [])`
* `ClosureIteratorAggregate`: `ClosureIteratorAggregate(callable $callable, array $arguments = [])`
* `ConcatIterableAggregate`
* `FilterIterableAggregate`
* `InterruptableIterableAggregate`: `InterruptableIterableAggregate(iterable $iterable)`
* `IterableIterator`: `IterableIterator(iterable $iterable)`
* `IterableIteratorAggregate`: `IterableIteratorAggregate(iterable $iterable)`
* `MapIterableAggregate`
* `MersenneTwisterRNGIteratorAggregate`
* `MultipleIterableAggregate`
* `PackIterableAggregate`
Expand Down Expand Up @@ -72,6 +74,20 @@ foreach ($iterator as $key => $value); // This will work.
foreach ($iterator as $key => $value); // This will also work.
```

### FilterIterableAggregate

```php
<?php

$iterator = (new FilterIterableAggregate(
range(0, 5),
static fn (int $v, int $key, iterable $iterable): bool =>
0 === (($v + 2 * $key + count($iterable)) % 2)
));

foreach ($iterator as $filteredValue) {} // 0, 2, 4
```

### InterruptableIterableAggregate

Let you break the iterator at anytime.
Expand Down Expand Up @@ -101,6 +117,25 @@ foreach ($iterator as $generator => [$key, $value]) {
}
```

### MapIterableAggregate

```php
<?php

$iterator = (new MapIterableAggregate(
range('a', 'c'),
static fn (string $letter, int $key, iterable $iterable): string =>
sprintf(
'%s::%s::%s',
$key,
$letter,
gettype($iterable)
)
));

foreach ($iterator as $tranformedValue) {}
```

### MersenneTwisterRNGIteratorAggregate

```php
Expand Down
55 changes: 55 additions & 0 deletions src/FilterIterableAggregate.php
@@ -0,0 +1,55 @@
<?php

/**
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

declare(strict_types=1);

namespace loophp\iterators;

use Closure;
use Generator;
use IteratorAggregate;

/**
* @template TKey
* @template T
*
* @implements IteratorAggregate<TKey, T>
*/
final class FilterIterableAggregate implements IteratorAggregate
{
/**
* @var iterable<TKey, T>
*/
private iterable $iterable;

/**
* @var Closure(T, TKey, iterable<TKey, T>): bool
*/
private Closure $predicate;

/**
* @param iterable<TKey, T> $iterable
* @param (Closure(T, TKey, iterable<TKey, T>): bool) $predicate
*/
public function __construct(iterable $iterable, Closure $predicate)
{
$this->iterable = $iterable;
$this->predicate = $predicate;
}

/**
* @return Generator<TKey, T>
*/
public function getIterator(): Generator
{
foreach ($this->iterable as $key => $value) {
if (($this->predicate)($value, $key, $this->iterable)) {
yield $key => $value;
}
}
}
}
54 changes: 54 additions & 0 deletions src/MapIterableAggregate.php
@@ -0,0 +1,54 @@
<?php

/**
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

declare(strict_types=1);

namespace loophp\iterators;

use Closure;
use Generator;
use IteratorAggregate;

/**
* @template TKey
* @template T
* @template W
*
* @implements IteratorAggregate<TKey, W>
*/
final class MapIterableAggregate implements IteratorAggregate
{
/**
* @var Closure(T, TKey, iterable<TKey, T>): W
*/
private Closure $closure;

/**
* @var iterable<TKey, T>
*/
private iterable $iterable;

/**
* @param iterable<TKey, T> $iterable
* @param (Closure(T, TKey, iterable<TKey, T>): W) $closure
*/
public function __construct(iterable $iterable, Closure $closure)
{
$this->iterable = $iterable;
$this->closure = $closure;
}

/**
* @return Generator<TKey, W>
*/
public function getIterator(): Generator
{
foreach ($this->iterable as $key => $value) {
yield $key => ($this->closure)($value, $key, $this->iterable);
}
}
}
37 changes: 37 additions & 0 deletions tests/unit/FilterIterableAggregateTest.php
@@ -0,0 +1,37 @@
<?php

/**
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

declare(strict_types=1);

namespace tests\loophp\iterators;

use loophp\iterators\FilterIterableAggregate;
use PHPUnit\Framework\TestCase;
use function count;

/**
* @internal
* @coversDefaultClass \loophp\iterators
*/
final class FilterIterableAggregateTest extends TestCase
{
public function testBasic(): void
{
$iterator = (new FilterIterableAggregate(
range(0, 5),
static fn (int $v, int $key, iterable $iterable): bool => 0 === (($v + 2 * $key + count($iterable)) % 2)
));

$expected = [
0 => 0,
2 => 2,
4 => 4,
];

self::assertSame($expected, iterator_to_array($iterator));
}
}
37 changes: 37 additions & 0 deletions tests/unit/MapIterableAggregateTest.php
@@ -0,0 +1,37 @@
<?php

/**
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

declare(strict_types=1);

namespace tests\loophp\iterators;

use loophp\iterators\MapIterableAggregate;
use PHPUnit\Framework\TestCase;
use function gettype;

/**
* @internal
* @coversDefaultClass \loophp\iterators
*/
final class MapIterableAggregateTest extends TestCase
{
public function testBasic(): void
{
$iterator = (new MapIterableAggregate(
range('a', 'c'),
static fn (string $letter, int $key, iterable $iterable): string => sprintf('%s::%s::%s', $key, $letter, gettype($iterable))
));

$expected = [
'0::a::array',
'1::b::array',
'2::c::array',
];

self::assertSame($expected, iterator_to_array($iterator));
}
}

0 comments on commit 6ea3e45

Please sign in to comment.