Skip to content

Commit

Permalink
feat: introduce search_opt_k_v
Browse files Browse the repository at this point in the history
Currently, there's no way to search iterable using also a key
  • Loading branch information
simPod committed Sep 12, 2024
1 parent 43eefa8 commit 86984c9
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/component/iter.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- [rewindable](./../../src/Psl/Iter/rewindable.php#L20)
- [search](./../../src/Psl/Iter/search.php#L28)
- [search_opt](./../../src/Psl/Iter/search_opt.php#L30)
- [search_opt_k_v](./../../src/Psl/Iter/search_opt_k_v.php#L31)
- [to_iterator](./../../src/Psl/Iter/to_iterator.php#L19)

#### `Classes`
Expand Down
1 change: 1 addition & 0 deletions src/Psl/Internal/Loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ final class Loader
'Psl\\Iter\\rewindable' => 'Psl/Iter/rewindable.php',
'Psl\\Iter\\search' => 'Psl/Iter/search.php',
'Psl\\Iter\\search_opt' => 'Psl/Iter/search_opt.php',
'Psl\\Iter\\search_opt_k_v' => 'Psl/Iter/search_opt_k_v.php',
'Psl\\Iter\\to_iterator' => 'Psl/Iter/to_iterator.php',
'Psl\\Vec\\chunk' => 'Psl/Vec/chunk.php',
'Psl\\Vec\\chunk_with_keys' => 'Psl/Vec/chunk_with_keys.php',
Expand Down
40 changes: 40 additions & 0 deletions src/Psl/Iter/search_opt_k_v.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace Psl\Iter;

use Closure;
use Psl\Option\Option;

/**
* Searches an iterable until a predicate returns true, then returns
* the value of the matching element wrapped in {@see Option::some}.
* If a predicate never returns true, {@see Option::none} will be returned.
*
* Examples:
*
* Iter\search_opt_k_v(['foo', 'bar', 'baz'], fn($k, $v) => 'baz' === $v)
* => Option::some('baz')
*
* Iter\search_opt_k_v(['foo', 'bar', 'baz'], fn($k, $v) => 'qux' === $v)
* => Option::none()
*
* @template TKey
* @template TValue
*
* @param iterable<TKey, TValue> $iterable The iterable to search
* @param (Closure(TKey, TValue): bool) $predicate
*
* @return Option<TValue>
*/
function search_opt_k_v(iterable $iterable, Closure $predicate): Option
{
foreach ($iterable as $key => $value) {
if ($predicate($key, $value)) {
return Option::some($value);
}
}

return Option::none();
}
42 changes: 42 additions & 0 deletions tests/unit/Iter/SearchOptKVTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Psl\Tests\Unit\Iter;

use PHPUnit\Framework\TestCase;
use Psl\Iter;

final class SearchOptKVTest extends TestCase
{
/**
* @dataProvider provideDataSome
*/
public function testSearchSome($expected, iterable $iterable, callable $predicate): void
{
static::assertSame($expected, Iter\search_opt_k_v($iterable, $predicate)->unwrap());
}

public function provideDataSome(): iterable
{
yield ['baz', ['foo', 'bar', 'baz'], static fn (int $k, string $v): bool => 2 === $k && 'baz' === $v];

yield [
'baz',
Iter\to_iterator(['foo', 'bar', 'baz']), static fn (int $k, string $v): bool => 2 === $k && 'baz' === $v
];
}
/**
* @dataProvider provideDataNone
*/
public function testSearchNone(iterable $iterable, callable $predicate): void
{
static::assertTrue(Iter\search_opt_k_v($iterable, $predicate)->isNone());
}
public function provideDataNone(): iterable
{
yield [[], static fn (int $k, string $v): bool => 'qux' === $v];
yield [Iter\to_iterator([]), static fn (int $k, string $v): bool => 'qux' === $v];
yield [Iter\to_iterator(['foo', 'bar', 'baz']), static fn (int $k, string $v): bool => 'qux' === $v];
}
}

0 comments on commit 86984c9

Please sign in to comment.