[Dict] add unique_scalar() function to avoid performance penalty hit when using Dict\unique() on large scalar arrays (#168)

Co-authored-by: yivi <ivan@yivoff.com>
This commit is contained in:
pencil-dog 2021-03-25 11:36:08 +01:00 committed by GitHub
parent 903aab0360
commit dcb13b9586
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 86 additions and 0 deletions

View File

@ -49,5 +49,6 @@
- [take_while](./../../src/Psl/Dict/take_while.php#L26)
- [unique](./../../src/Psl/Dict/unique.php#L17)
- [unique_by](./../../src/Psl/Dict/unique_by.php#L23)
- [unique_scalar](./../../src/Psl/Dict/unique_scalar.php#L21)

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Psl\Dict;
use function array_unique;
use function is_array;
/**
* Returns a new dict in which each value appears exactly once. Better performant than `Dict\unique()` when the values
* are only scalars.
*
* @template Tk of array-key
* @template Tv of scalar
*
* @param iterable<Tk, Tv> $iterable
*
* @return array<Tk, Tv>
*/
function unique_scalar(iterable $iterable): array
{
if (is_array($iterable)) {
return array_unique($iterable);
}
return unique_by(
$iterable,
/**
* @param scalar $v
*
* @return scalar
*
* @pure
*/
static fn($v) => $v
);
}

View File

@ -136,6 +136,7 @@ final class Loader
'Psl\Dict\take_while',
'Psl\Dict\unique',
'Psl\Dict\unique_by',
'Psl\Dict\unique_scalar',
'Psl\Dict\diff',
'Psl\Dict\diff_by_key',
'Psl\Dict\intersect',

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Dict;
use PHPUnit\Framework\TestCase;
use Psl\Collection;
use Psl\Dict;
use Psl\Iter;
use Psl\Vec;
final class UniqueScalarTest extends TestCase
{
public function testUniqueScalars(): void
{
$array = Vec\fill(10, 'foo');
$array[] = 'bar';
$unique = Dict\unique_scalar($array);
static::assertCount(2, $unique);
static::assertSame(['foo', 'bar'], Vec\values($unique));
}
public function testUniqueIterator()
{
$array = Iter\Iterator::create(['foo', 'foo', 'bar', 'bar', 'baz']);
$unique = Dict\unique_scalar($array);
static::assertCount(3, $unique);
static::assertSame(['foo', 'bar', 'baz'], Vec\values($unique));
}
public function testUniqueIteratorAgggregate()
{
$array = Collection\Map::fromArray(['foo', 'foo', 'bar', 'bar', 'baz']);
$unique = Dict\unique_scalar($array);
static::assertCount(3, $unique);
static::assertSame(['foo', 'bar', 'baz'], Vec\values($unique));
}
}