Skip to content

Commit

Permalink
Add Vec versions of the unique functions (#472)
Browse files Browse the repository at this point in the history
Vec counterparts for the Dict versions of these functions
  • Loading branch information
BackEndTea authored May 4, 2024
1 parent 8ea808a commit 7efaf75
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/component/vec.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
- [sort](./../../src/Psl/Vec/sort.php#L25)
- [sort_by](./../../src/Psl/Vec/sort_by.php#L28)
- [take](./../../src/Psl/Vec/take.php#L22)
- [unique](./../../src/Psl/Vec/unique.php#L16)
- [unique_by](./../../src/Psl/Vec/unique_by.php#L23)
- [unique_scalar](./../../src/Psl/Vec/unique_scalar.php#L20)
- [values](./../../src/Psl/Vec/values.php#L19)
- [zip](./../../src/Psl/Vec/zip.php#L37)

Expand Down
3 changes: 3 additions & 0 deletions src/Psl/Internal/Loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ final class Loader
'Psl\\Vec\\sort' => 'Psl/Vec/sort.php',
'Psl\\Vec\\sort_by' => 'Psl/Vec/sort_by.php',
'Psl\\Vec\\take' => 'Psl/Vec/take.php',
'Psl\\Vec\\unique' => 'Psl/Vec/unique.php',
'Psl\\Vec\\unique_by' => 'Psl/Vec/unique_by.php',
'Psl\\Vec\\unique_scalar' => 'Psl/Vec/unique_scalar.php',
'Psl\\Vec\\values' => 'Psl/Vec/values.php',
'Psl\\Vec\\zip' => 'Psl/Vec/zip.php',
'Psl\\Math\\abs' => 'Psl/Math/abs.php',
Expand Down
29 changes: 29 additions & 0 deletions src/Psl/Vec/unique.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Psl\Vec;

/**
* Return all the unique values of an array, as a list.
*
* @template Tv
*
* @param iterable<Tv> $iterable
*
* @return list<Tv>
*/
function unique(iterable $iterable): array
{
return namespace\unique_by(
$iterable,
/**
* @param Tv $v
*
* @return Tv
*
* @pure
*/
static fn($v) => $v,
);
}
39 changes: 39 additions & 0 deletions src/Psl/Vec/unique_by.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Psl\Vec;

use Closure;
use Psl\Iter;

/**
* Returns a new array in which each value appears exactly once, where the
* value's uniqueness is determined by transforming it to a scalar via the
* given function.
*
* @template Tv
* @template Ts
*
* @param iterable<Tv> $iterable
* @param (Closure(Tv): Ts) $scalar_func
*
* @return list<Tv>
*/
function unique_by(iterable $iterable, Closure $scalar_func): array
{
/** @var list<Ts> $unique */
$unique = [];
/** @var list<Tv> $original_values */
$original_values = [];
foreach ($iterable as $v) {
$scalar = $scalar_func($v);

if (!Iter\contains($unique, $scalar)) {
$unique[] = $scalar;
$original_values[] = $v;
}
}

return $original_values;
}
37 changes: 37 additions & 0 deletions src/Psl/Vec/unique_scalar.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Psl\Vec;

use function array_unique;
use function is_array;

/**
* Returns a new list in which each value appears exactly once. Better performant than `Vec\unique()` when the values
* are only scalars.
*
* @template Tv of scalar
*
* @param iterable<Tv> $iterable
*
* @return list<Tv>
*/
function unique_scalar(iterable $iterable): array
{
if (is_array($iterable)) {
return namespace\values(array_unique($iterable));
}

return unique_by(
$iterable,
/**
* @param scalar $v
*
* @return scalar
*
* @pure
*/
static fn($v) => $v
);
}
37 changes: 37 additions & 0 deletions tests/unit/Vec/UniqueByTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Psl\Tests\Unit\Vec;

use PHPUnit\Framework\TestCase;
use Psl\Str;
use Psl\Vec;

final class UniqueByTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testUniqueBy(array $expected, array $array, callable $scalar_fun): void
{
static::assertSame($expected, Vec\unique_by($array, $scalar_fun));
}

public function provideData(): array
{
return [
[
['a', 'saif'],
['a', 'b', 'c', 'd', 'saif', 'jack'],
static fn (string $value): int => Str\length($value),
],

[
['foo', 'bar', '@baz'],
['foo', '@foo', 'bar', '@bar', '@baz'],
static fn (string $value): string => Str\replace($value, '@', ''),
],
];
}
}
44 changes: 44 additions & 0 deletions tests/unit/Vec/UniqueScalarTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Psl\Tests\Unit\Vec;

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

final class UniqueScalarTest extends TestCase
{
public function testUniqueScalars(): void
{
$array = Vec\fill(10, 'foo');
$array[] = 'bar';

$unique = Vec\unique_scalar($array);

static::assertCount(2, $unique);
static::assertSame(['foo', 'bar'], $unique);
}

public function testUniqueIterator()
{
$array = Iter\Iterator::create(['foo', 'foo', 'bar', 'bar', 'baz']);

$unique = Vec\unique_scalar($array);

static::assertCount(3, $unique);
static::assertSame(['foo', 'bar', 'baz'], $unique);
}

public function testUniqueIteratorAgggregate()
{
$array = Collection\Map::fromArray(['foo', 'foo', 'bar', 'bar', 'baz']);

$unique = Vec\unique_scalar($array);

static::assertCount(3, $unique);
static::assertSame(['foo', 'bar', 'baz'], $unique);
}
}
38 changes: 38 additions & 0 deletions tests/unit/Vec/UniqueTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Psl\Tests\Unit\Vec;

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

final class UniqueTest extends TestCase
{
public function testUnique(): void
{
$array = Vec\fill(10, 'foo');

$unique = Vec\unique($array);

static::assertCount(1, $unique);

static::assertSame('foo', Iter\first($unique));
}

public function testUniqueWithObjects(): void
{
$array = Vec\fill(10, 'foo');
$object = new Collection\Map([]);
$array = Vec\concat($array, Vec\fill(10, $object));

$unique = Vec\unique($array);

static::assertCount(2, $unique);

static::assertSame('foo', Iter\first($unique));
static::assertSame($object, Iter\last($unique));
}
}

0 comments on commit 7efaf75

Please sign in to comment.