[Dict] add intersect and diff functions (#137)

This commit is contained in:
Saif Eddin Gmati 2021-02-20 20:48:20 +01:00 committed by GitHub
parent 781e8d5017
commit 2af0f628d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 328 additions and 0 deletions

42
src/Psl/Dict/diff.php Normal file
View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Psl\Dict;
use Psl\Iter;
use Psl\Vec;
use function array_diff;
/**
* Computes the difference of iterables.
*
* @psalm-template Tk of array-key
* @psalm-template Tv
*
* @psalm-param iterable<Tk, Tv> $first
* @psalm-param iterable<Tk, Tv> $second
* @psalm-param iterable<Tk, Tv> ...$rest
*
* @psalm-return array<Tk, Tv>
*/
function diff(iterable $first, iterable $second, iterable ...$rest): array
{
if (Iter\is_empty($first)) {
return [];
}
return array_diff(from_iterable($first), from_iterable($second), ...Vec\map(
$rest,
/**
* @template Tk of array-key
* @template Tv
*
* @param iterable<Tk, Tv> $iterable
*
* @return array<Tk, Tv>
*/
static fn(iterable $iterable): array => from_iterable($iterable)
));
}

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Psl\Dict;
use Psl\Iter;
use Psl\Vec;
use function array_diff_key;
/**
* Computes the difference of iterables using keys for comparison.
*
* @psalm-template Tk of array-key
* @psalm-template Tv
*
* @psalm-param iterable<Tk, Tv> $first
* @psalm-param iterable<Tk, mixed> $second
* @psalm-param iterable<Tk, mixed> ...$rest
*
* @psalm-return array<Tk, Tv>
*/
function diff_by_key(iterable $first, iterable $second, iterable ...$rest): array
{
if (Iter\is_empty($first)) {
return [];
}
return array_diff_key(from_iterable($first), from_iterable($second), ...Vec\map(
$rest,
/**
* @template Tk of array-key
* @template Tv
*
* @param iterable<Tk, Tv> $iterable
*
* @return array<Tk, Tv>
*/
static fn(iterable $iterable): array => from_iterable($iterable)
));
}

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Psl\Dict;
use Psl\Iter;
use Psl\Vec;
use function array_intersect;
/**
* Computes the intersection of iterables.
*
* @template Tk of array-key
* @template Tv
*
* @param iterable<Tk, Tv> $first
* @param iterable<Tk, mixed> $second
* @param iterable<Tk, mixed> ...$rest
*
* @return array<Tk, Tv>
*/
function intersect(iterable $first, iterable $second, iterable ...$rest): array
{
if (Iter\is_empty($first)) {
return [];
}
return array_intersect(from_iterable($first), from_iterable($second), ...Vec\map(
$rest,
/**
* @template Tk of array-key
* @template Tv
*
* @param iterable<Tk, Tv> $iterable
*
* @return array<Tk, Tv>
*/
static fn(iterable $iterable): array => from_iterable($iterable)
));
}

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Psl\Dict;
use Psl\Iter;
use Psl\Vec;
use function array_intersect_key;
/**
* Computes the intersection of iterables using keys for comparison.
*
* @template Tk of array-key
* @template Tv
*
* @param iterable<Tk, Tv> $first
* @param iterable<Tk, mixed> $second
* @param iterable<Tk, mixed> ...$rest
*
* @return array<Tk, Tv>
*/
function intersect_by_key(iterable $first, iterable $second, iterable ...$rest): array
{
if (Iter\is_empty($first)) {
return [];
}
return array_intersect_key(from_iterable($first), from_iterable($second), ...Vec\map(
$rest,
/**
* @template Tk of array-key
* @template Tv
*
* @param iterable<Tk, Tv> $iterable
*
* @return array<Tk, Tv>
*/
static fn(iterable $iterable): array => from_iterable($iterable)
));
}

View File

@ -129,6 +129,10 @@ final class Loader
'Psl\Dict\take_while', 'Psl\Dict\take_while',
'Psl\Dict\unique', 'Psl\Dict\unique',
'Psl\Dict\unique_by', 'Psl\Dict\unique_by',
'Psl\Dict\diff',
'Psl\Dict\diff_by_key',
'Psl\Dict\intersect',
'Psl\Dict\intersect_by_key',
'Psl\Fun\after', 'Psl\Fun\after',
'Psl\Fun\identity', 'Psl\Fun\identity',
'Psl\Fun\pipe', 'Psl\Fun\pipe',

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Psl\Iter; namespace Psl\Iter;
use Generator; use Generator;
use Psl\Vec;
/** /**
* Chains the iterables that were passed as arguments. * Chains the iterables that were passed as arguments.
@ -23,6 +24,10 @@ use Generator;
* @psalm-param iterable<Tk, Tv> ...$iterables Iterables to chain * @psalm-param iterable<Tk, Tv> ...$iterables Iterables to chain
* *
* @psalm-return Iterator<Tk, Tv> * @psalm-return Iterator<Tk, Tv>
*
* @deprecated use `Vec\concat` instead.
*
* @see Vec\concat()
*/ */
function chain(iterable ...$iterables): Iterator function chain(iterable ...$iterables): Iterator
{ {

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Psl\Iter; namespace Psl\Iter;
use Generator; use Generator;
use Psl\Dict;
/** /**
* @psalm-template Tk * @psalm-template Tk
@ -15,6 +16,10 @@ use Generator;
* @psalm-param iterable<Tk, mixed> ...$rest * @psalm-param iterable<Tk, mixed> ...$rest
* *
* @psalm-return Iterator<Tk, Tv> * @psalm-return Iterator<Tk, Tv>
*
* @deprecated use `Dict\diff_by_key` instead.
*
* @see Dict\diff_by_key()
*/ */
function diff_by_key(iterable $first, iterable $second, iterable ...$rest): Iterator function diff_by_key(iterable $first, iterable $second, iterable ...$rest): Iterator
{ {

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Dict;
use PHPUnit\Framework\TestCase;
use Psl\Dict;
use Psl\Vec;
final class DiffByKeyTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testDiffByKey(array $expected, iterable $first, iterable $second, iterable ...$rest): void
{
static::assertSame($expected, Dict\diff_by_key($first, $second, ...$rest));
}
public function provideData(): iterable
{
yield [[], [], [], []];
yield [[], [], [1, 2, 3]];
yield [[], [], [1, 2, 3], []];
yield [[], [], [1, 2, 3], [], [4, 5]];
yield [[1, 2], [1, 2], [], []];
yield [[1, 2], [1, 2], ['foo' => 2], []];
yield [[1, 2], [1, 2], [], ['baz' => 1]];
yield [[6 => 7, 7 => 8], Vec\range(1, 8), Vec\range(1, 6), []];
yield [[7 => 8], Vec\range(1, 8), Vec\range(1, 6), [6 => 7]];
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Dict;
use PHPUnit\Framework\TestCase;
use Psl\Dict;
use Psl\Vec;
final class DiffTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testDiff(array $expected, iterable $first, iterable $second, iterable ...$rest): void
{
static::assertSame($expected, Dict\diff($first, $second, ...$rest));
}
public function provideData(): iterable
{
yield [[], [], [], []];
yield [[], [], [1, 2, 3]];
yield [[], [], [1, 2, 3], []];
yield [[], [], [1, 2, 3], [], [4, 5]];
yield [[1, 2], [1, 2], [], []];
yield [[1], [1, 2], ['foo' => 2], []];
yield [[1 => 2], [1, 2], [], ['baz' => 1]];
yield [[], [1, 2], ['foo' => 2], ['baz' => 1]];
yield [[], [1, 2], ['foo' => 2], ['baz' => 1]];
yield [[6 => 7, 7 => 8], Vec\range(1, 8), Vec\range(1, 6), []];
yield [[7 => 8], Vec\range(1, 8), Vec\range(1, 6), [6 => 7]];
}
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Dict;
use PHPUnit\Framework\TestCase;
use Psl\Dict;
use Psl\Vec;
final class IntersectByKeyTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testIntersectByKey(array $expected, iterable $first, iterable $second, iterable ...$rest): void
{
static::assertSame($expected, Dict\intersect_by_key($first, $second, ...$rest));
}
public function provideData(): iterable
{
yield [[], [], [], []];
yield [[], [], [1, 2, 3]];
yield [[], [], [1, 2, 3], []];
yield [[], [], [1, 2, 3], [], [4, 5]];
yield [[], [1, 2], [], []];
yield [[], [1, 2], ['foo' => 2], []];
yield [[], [1, 2], [], ['baz' => 1]];
yield [[], [1, 2], ['foo' => 2], ['baz' => 1]];
yield [[], [1, 2], ['foo' => 2], ['baz' => 1]];
yield [[], [1, 2], ['foo' => 2, 'baz' => 1]];
yield [[1, 2, 3, 4, 5, 6], Vec\range(1, 8), Vec\range(1, 6)];
yield [[], Vec\range(1, 8), Vec\range(1, 6), []];
yield [[5 => 6], Vec\range(1, 8), Vec\range(1, 6), [5 => 6, 6 => 7]];
}
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Psl\Tests\Dict;
use PHPUnit\Framework\TestCase;
use Psl\Dict;
use Psl\Vec;
final class IntersectTest extends TestCase
{
/**
* @dataProvider provideData
*/
public function testIntersect(array $expected, iterable $first, iterable $second, iterable ...$rest): void
{
static::assertSame($expected, Dict\intersect($first, $second, ...$rest));
}
public function provideData(): iterable
{
yield [[], [], [], []];
yield [[], [], [1, 2, 3]];
yield [[], [], [1, 2, 3], []];
yield [[], [], [1, 2, 3], [], [4, 5]];
yield [[], [1, 2], [], []];
yield [[], [1, 2], ['foo' => 2], []];
yield [[], [1, 2], [], ['baz' => 1]];
yield [[], [1, 2], ['foo' => 2], ['baz' => 1]];
yield [[], [1, 2], ['foo' => 2], ['baz' => 1]];
yield [[1, 2], [1, 2], ['foo' => 2, 'baz' => 1]];
yield [[1, 2, 3, 4, 5, 6], Vec\range(1, 8), Vec\range(1, 6)];
yield [[], Vec\range(1, 8), Vec\range(1, 6), []];
yield [[5 => 6], Vec\range(1, 8), Vec\range(1, 6), [5 => 6, 6 => 7]];
}
}