Skip to content

Commit

Permalink
added Arrays::firstKey(), lastKey()
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Nov 30, 2023
1 parent 5767b8e commit 410e508
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/Utils/Arrays.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,36 @@ public static function last(array $array): mixed
}


/**
* Returns the key of first item (matching the specified predicate if given) or null if there is no such item.
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
*/
public static function firstKey(array $array, ?callable $predicate = null): int|string|null
{
if (!$predicate) {
return array_key_first($array);
}
foreach ($array as $k => $v) {
if ($predicate($v, $k, $array)) {
return $k;
}
}
return null;
}


/**
* Returns the key of last item (matching the specified predicate if given) or null if there is no such item.
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
*/
public static function lastKey(array $array, ?callable $predicate = null): int|string|null
{
return $predicate
? self::firstKey(array_reverse($array, preserve_keys: true), $predicate)
: array_key_last($array);
}


/**
* Inserts the contents of the $inserted array into the $array immediately after the $key.
* If $key is null (or does not exist), it is inserted at the beginning.
Expand Down
39 changes: 39 additions & 0 deletions tests/Utils/Arrays.firstKey().phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

use Nette\Utils\Arrays;
use Tester\Assert;

require __DIR__ . '/../bootstrap.php';


test('no predicate', function () {
Assert::null(Arrays::firstKey([]));
Assert::same(0, Arrays::firstKey([null]));
Assert::same(0, Arrays::firstKey([1, 2, 3]));
Assert::same(5, Arrays::firstKey([5 => 1, 2, 3]));
});

test('internal array pointer is not affected', function () {
$arr = [1, 2, 3];
end($arr);
Assert::same(0, Arrays::firstKey($arr));
Assert::same(3, current($arr));
});

test('with predicate', function () {
Assert::null(Arrays::firstKey([], fn() => true));
Assert::null(Arrays::firstKey([], fn() => false));
Assert::null(Arrays::firstKey(['' => 'x'], fn() => false));
Assert::same(0, Arrays::firstKey([null], fn() => true));
Assert::null(Arrays::firstKey([null], fn() => false));
Assert::same(0, Arrays::firstKey([1, 2, 3], fn() => true));
Assert::null(Arrays::firstKey([1, 2, 3], fn() => false));
Assert::same(2, Arrays::firstKey([1, 2, 3], fn($v) => $v > 2));
Assert::same(0, Arrays::firstKey([1, 2, 3], fn($v) => $v < 2));
});

test('predicate arguments', function () {
Arrays::firstKey([2 => 'x'], fn() => Assert::same(['x', 2, [2 => 'x']], func_get_args()));
});
38 changes: 38 additions & 0 deletions tests/Utils/Arrays.lastKey().phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

use Nette\Utils\Arrays;
use Tester\Assert;

require __DIR__ . '/../bootstrap.php';


test('no predicate', function () {
Assert::null(Arrays::lastKey([]));
Assert::same(0, Arrays::lastKey([null]));
Assert::same(2, Arrays::lastKey([1, 2, 3]));
Assert::same(7, Arrays::lastKey([5 => 1, 2, 3]));
});

test('internal array pointer is not affected', function () {
$arr = [1, 2, 3];
Assert::same(2, Arrays::lastKey($arr));
Assert::same(1, current($arr));
});

test('with predicate', function () {
Assert::null(Arrays::lastKey([], fn() => true));
Assert::null(Arrays::lastKey([], fn() => false));
Assert::null(Arrays::lastKey(['' => 'x'], fn() => false));
Assert::same(0, Arrays::lastKey([null], fn() => true));
Assert::null(Arrays::lastKey([null], fn() => false));
Assert::same(2, Arrays::lastKey([1, 2, 3], fn() => true));
Assert::null(Arrays::lastKey([1, 2, 3], fn() => false));
Assert::same(2, Arrays::lastKey([1, 2, 3], fn($v) => $v > 2));
Assert::same(0, Arrays::lastKey([1, 2, 3], fn($v) => $v < 2));
});

test('predicate arguments', function () {
Arrays::lastKey([2 => 'x'], fn() => Assert::same(['x', 2, [2 => 'x']], func_get_args()));
});

0 comments on commit 410e508

Please sign in to comment.