Skip to content

Commit c2cc29c

Browse files
committed
added Arrays::firstKey(), lastKey()
1 parent a445024 commit c2cc29c

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

src/Utils/Arrays.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,36 @@ public static function last(array $array): mixed
144144
}
145145

146146

147+
/**
148+
* Returns the key of first item (matching the specified predicate if given) or null if there is no such item.
149+
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
150+
*/
151+
public static function firstKey(array $array, ?callable $predicate = null): int|string|null
152+
{
153+
if (!$predicate) {
154+
return array_key_first($array);
155+
}
156+
foreach ($array as $k => $v) {
157+
if ($predicate($v, $k, $array)) {
158+
return $k;
159+
}
160+
}
161+
return null;
162+
}
163+
164+
165+
/**
166+
* Returns the key of last item (matching the specified predicate if given) or null if there is no such item.
167+
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
168+
*/
169+
public static function lastKey(array $array, ?callable $predicate = null): int|string|null
170+
{
171+
return $predicate
172+
? self::firstKey(array_reverse($array, preserve_keys: true), $predicate)
173+
: array_key_last($array);
174+
}
175+
176+
147177
/**
148178
* Inserts the contents of the $inserted array into the $array immediately after the $key.
149179
* If $key is null (or does not exist), it is inserted at the beginning.

tests/Utils/Arrays.firstKey().phpt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Nette\Utils\Arrays;
6+
use Tester\Assert;
7+
8+
require __DIR__ . '/../bootstrap.php';
9+
10+
11+
test('no predicate', function () {
12+
Assert::null(Arrays::firstKey([]));
13+
Assert::same(0, Arrays::firstKey([null]));
14+
Assert::same(0, Arrays::firstKey([1, 2, 3]));
15+
Assert::same(5, Arrays::firstKey([5 => 1, 2, 3]));
16+
});
17+
18+
test('internal array pointer is not affected', function () {
19+
$arr = [1, 2, 3];
20+
end($arr);
21+
Assert::same(0, Arrays::firstKey($arr));
22+
Assert::same(3, current($arr));
23+
});
24+
25+
test('with predicate', function () {
26+
Assert::null(Arrays::firstKey([], fn() => true));
27+
Assert::null(Arrays::firstKey([], fn() => false));
28+
Assert::null(Arrays::firstKey(['' => 'x'], fn() => false));
29+
Assert::same(0, Arrays::firstKey([null], fn() => true));
30+
Assert::null(Arrays::firstKey([null], fn() => false));
31+
Assert::same(0, Arrays::firstKey([1, 2, 3], fn() => true));
32+
Assert::null(Arrays::firstKey([1, 2, 3], fn() => false));
33+
Assert::same(2, Arrays::firstKey([1, 2, 3], fn($v) => $v > 2));
34+
Assert::same(0, Arrays::firstKey([1, 2, 3], fn($v) => $v < 2));
35+
});
36+
37+
test('predicate arguments', function () {
38+
Arrays::firstKey([2 => 'x'], fn() => Assert::same(['x', 2, [2 => 'x']], func_get_args()));
39+
});

tests/Utils/Arrays.lastKey().phpt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Nette\Utils\Arrays;
6+
use Tester\Assert;
7+
8+
require __DIR__ . '/../bootstrap.php';
9+
10+
11+
test('no predicate', function () {
12+
Assert::null(Arrays::lastKey([]));
13+
Assert::same(0, Arrays::lastKey([null]));
14+
Assert::same(2, Arrays::lastKey([1, 2, 3]));
15+
Assert::same(7, Arrays::lastKey([5 => 1, 2, 3]));
16+
});
17+
18+
test('internal array pointer is not affected', function () {
19+
$arr = [1, 2, 3];
20+
Assert::same(2, Arrays::lastKey($arr));
21+
Assert::same(1, current($arr));
22+
});
23+
24+
test('with predicate', function () {
25+
Assert::null(Arrays::lastKey([], fn() => true));
26+
Assert::null(Arrays::lastKey([], fn() => false));
27+
Assert::null(Arrays::lastKey(['' => 'x'], fn() => false));
28+
Assert::same(0, Arrays::lastKey([null], fn() => true));
29+
Assert::null(Arrays::lastKey([null], fn() => false));
30+
Assert::same(2, Arrays::lastKey([1, 2, 3], fn() => true));
31+
Assert::null(Arrays::lastKey([1, 2, 3], fn() => false));
32+
Assert::same(2, Arrays::lastKey([1, 2, 3], fn($v) => $v > 2));
33+
Assert::same(0, Arrays::lastKey([1, 2, 3], fn($v) => $v < 2));
34+
});
35+
36+
test('predicate arguments', function () {
37+
Arrays::lastKey([2 => 'x'], fn() => Assert::same(['x', 2, [2 => 'x']], func_get_args()));
38+
});

0 commit comments

Comments
 (0)