Skip to content

Commit

Permalink
filter |sort: added by & byKey [WIP]
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Dec 7, 2023
1 parent e34e855 commit 366c426
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 20 deletions.
39 changes: 29 additions & 10 deletions src/Latte/Essential/Filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,23 @@ public static function batch(iterable $list, int $length, $rest = null): \Genera
/**
* Sorts elements using the comparison function and preserves the key association.
*/
public static function sort(iterable $iterable, ?\Closure $comparison = null): iterable
{
public static function sort(
iterable $iterable,
?\Closure $comparison = null,
bool $byKey = false,
string|int|\Closure|null $by = null,
): iterable
{
// TODO: support for intl collate
$comparison ??= fn($a, $b) => $a <=> $b;
$comparison = match (true) {
$by === null => $comparison,
$by instanceof \Closure => fn($a, $b) => $comparison($by($a), $by($b)),
default => fn($a, $b) => $comparison(is_array($a) ? $a[$by] : $a->$by, is_array($b) ? $b[$by] : $b->$by),
};

if (is_array($iterable)) {
$comparison ? uasort($iterable, $comparison) : asort($iterable);
$byKey ? uksort($iterable, $comparison) : uasort($iterable, $comparison);
return $iterable;
}

Expand All @@ -469,13 +482,19 @@ public static function sort(iterable $iterable, ?\Closure $comparison = null): i
$keys[] = $key;
$values[] = $value;
}
$comparison ? uasort($values, $comparison) : asort($values);

return (static function () use ($keys, $values): \Generator {
foreach ($values as $i => $value) {
yield $keys[$i] => $value;
}
})();
$byKey ? uasort($keys, $comparison) : uasort($values, $comparison);

return $byKey
? (static function () use ($keys, $values): \Generator {
foreach ($keys as $i => $key) {
yield $key => $values[$i];
}
})()
: (static function () use ($keys, $values): \Generator {
foreach ($values as $i => $value) {
yield $keys[$i] => $value;
}
})();
}


Expand Down
131 changes: 121 additions & 10 deletions tests/filters/sort.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ require __DIR__ . '/../bootstrap.php';

function iterator(): Generator
{
yield 'a' => 20;
yield 'b' => 10;
yield [true] => 30;
yield ['a' => 55] => ['k' => 22];
yield ['a' => 66] => (object) ['k' => 11];
yield ['a' => 77] => ['k' => 33];
}


Expand All @@ -31,30 +31,141 @@ function exportIterator(Traversable $iterator): array


test('array', function () {
Assert::same([1 => 10, 0 => 20, 30], Filters::sort([20, 10, 30]));
Assert::same([1 => 11, 0 => 22, 33], Filters::sort([22, 11, 33]));
Assert::same([], Filters::sort([]));
});


test('iterator', function () {
Assert::same(
[['b', 10], ['a', 20], [[true], 30]],
Assert::equal(
[
[['a' => 55], ['k' => 22]],
[['a' => 77], ['k' => 33]],
[['a' => 66], (object) ['k' => 11]],
],
exportIterator(Filters::sort(iterator())),
);
});


test('user comparison + array', function () {
Assert::same(
[2 => 30, 0 => 20, 1 => 10],
Filters::sort([20, 10, 30], fn($a, $b) => $b <=> $a)
[2 => 33, 0 => 22, 1 => 11],
Filters::sort([22, 11, 33], fn($a, $b) => $b <=> $a)
);
});


test('user comparison + iterator', function () {
Assert::same(
[[[true], 30], ['a', 20], ['b', 10]],
Assert::equal(
[
[['a' => 66], (object) ['k' => 11]],
[['a' => 77], ['k' => 33]],
[['a' => 55], ['k' => 22]],
],
exportIterator(Filters::sort(iterator(), fn($a, $b) => $b <=> $a)),
);
});


test('array + by', function () {
Assert::equal(
[1 => (object) ['k' => 11], 0 => ['k' => 22], ['k' => 33]],
Filters::sort([['k' => 22], (object) ['k' => 11], ['k' => 33]], by: 'k'),
);
Assert::same([], Filters::sort([], by: 'k'));
});


test('iterator + by', function () {
Assert::equal(
[
[['a' => 66], (object) ['k' => 11]],
[['a' => 55], ['k' => 22]],
[['a' => 77], ['k' => 33]],
],
exportIterator(Filters::sort(iterator(), by: 'k')),
);
});


test('callback + array + by', function () {
Assert::same(
[1 => 11, 0 => 22, 33],
Filters::sort([22, 11, 33], by: fn($a) => $a * 11)
);
});


test('callback + iterator + by', function () {
Assert::equal(
[
[['a' => 77], ['k' => 33]],
[['a' => 55], ['k' => 22]],
[['a' => 66], (object) ['k' => 11]],
],
exportIterator(Filters::sort(iterator(), by: fn($a) => -((array) $a)['k'])),
);
});


test('array + byKey', function () {
Assert::same([1 => 11, 0 => 22, 33], Filters::sort([22, 11, 33]));
Assert::same([], Filters::sort([], byKey: true));
});


test('iterator + byKey', function () {
Assert::equal(
[
[['a' => 55], ['k' => 22]],
[['a' => 66], (object) ['k' => 11]],
[['a' => 77], ['k' => 33]],
],
exportIterator(Filters::sort(iterator(), byKey: true)),
);
});


test('user comparison + array + byKey', function () {
Assert::same(
[2 => 33, 1 => 11, 0 => 22],
Filters::sort([22, 11, 33], fn($a, $b) => $b <=> $a, byKey: true),
);
});


test('user comparison + iterator + byKey', function () {
Assert::equal(
[
[['a' => 77], ['k' => 33]],
[['a' => 66], (object) ['k' => 11]],
[['a' => 55], ['k' => 22]],
],
exportIterator(Filters::sort(iterator(), fn($a, $b) => $b <=> $a, byKey: true)),
);
});


test('iterator + by + byKey', function () {
Assert::equal(
[
[['a' => 55], ['k' => 22]],
[['a' => 66], (object) ['k' => 11]],
[['a' => 77], ['k' => 33]],
],
exportIterator(Filters::sort(iterator(), byKey: true, by: 'a')),
);
});


test('callback + iterator + by + byKey', function () {
Assert::equal(
[
[['a' => 77], ['k' => 33]],
[['a' => 66], (object) ['k' => 11]],
[['a' => 55], ['k' => 22]],
],
exportIterator(Filters::sort(iterator(), byKey: true, by: fn($a) => -((array) $a)['a'])),
);
});

0 comments on commit 366c426

Please sign in to comment.