Skip to content

Commit 8f52e4a

Browse files
authored
feat(support): add sorting methods to ArrayHelper (#659)
1 parent 32bf4d0 commit 8f52e4a

File tree

2 files changed

+163
-3
lines changed

2 files changed

+163
-3
lines changed

src/Tempest/Support/src/ArrayHelper.php

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -768,12 +768,85 @@ public function mapTo(string $to): self
768768
}
769769

770770
/**
771-
* Sorts the array in ascending order.
771+
* Returns a new instance of this array sorted by its values.
772+
*
773+
* @param bool $desc Sorts in descending order if `true`; defaults to `false` (ascending).
774+
* @param bool|null $preserveKeys Preserves array keys if `true`; reindexes numerically if `false`.
775+
* Defaults to `null`, which auto-detects preservation based on array type (associative or list).
776+
* @param int $flags Sorting flags to define comparison behavior, defaulting to `SORT_REGULAR`.
777+
* @return self<array-key, TValue> Key type depends on whether array keys are preserved or not.
778+
*/
779+
public function sort(bool $desc = false, ?bool $preserveKeys = null, int $flags = SORT_REGULAR): self
780+
{
781+
$array = $this->array;
782+
783+
if ($preserveKeys === null) {
784+
$preserveKeys = $this->isAssoc();
785+
}
786+
787+
if ($preserveKeys) {
788+
$desc ? arsort($array, $flags) : asort($array, $flags);
789+
} else {
790+
$desc ? rsort($array, $flags) : sort($array, $flags);
791+
}
792+
793+
return new self($array);
794+
}
795+
796+
/**
797+
* Returns a new instance of this array sorted by its values using a callback function.
798+
*
799+
* @param callable $callback The function to use for comparing values. It should accept two parameters
800+
* and return an integer less than, equal to, or greater than zero if the
801+
* first argument is considered to be respectively less than, equal to, or
802+
* greater than the second.
803+
* @param bool|null $preserveKeys Preserves array keys if `true`; reindexes numerically if `false`.
804+
* Defaults to `null`, which auto-detects preservation based on array type (associative or list).
805+
* @return self<array-key, TValue> Key type depends on whether array keys are preserved or not.
806+
*/
807+
public function sortByCallback(callable $callback, ?bool $preserveKeys = null): self
808+
{
809+
$array = $this->array;
810+
811+
if ($preserveKeys === null) {
812+
$preserveKeys = $this->isAssoc();
813+
}
814+
815+
$preserveKeys ? uasort($array, $callback) : usort($array, $callback);
816+
817+
return new self($array);
818+
}
819+
820+
/**
821+
* Returns a new instance of this array sorted by its keys.
822+
*
823+
* @param bool $desc Sorts in descending order if `true`; defaults to `false` (ascending).
824+
* @param int $flags Sorting flags to define comparison behavior, defaulting to `SORT_REGULAR`.
825+
* @return self<TKey, TValue>
826+
*/
827+
public function sortKeys(bool $desc = false, int $flags = SORT_REGULAR): self
828+
{
829+
$array = $this->array;
830+
831+
$desc ? krsort($array, $flags) : ksort($array, $flags);
832+
833+
return new self($array);
834+
}
835+
836+
/**
837+
* Returns a new instance of this array sorted by its keys using a callback function.
838+
*
839+
* @param callable $callback The function to use for comparing keys. It should accept two parameters
840+
* and return an integer less than, equal to, or greater than zero if the
841+
* first argument is considered to be respectively less than, equal to, or
842+
* greater than the second.
843+
* @return self<TKey, TValue>
772844
*/
773-
public function sort(): self
845+
public function sortKeysByCallback(callable $callback): self
774846
{
775847
$array = $this->array;
776-
sort($array);
848+
849+
uksort($array, $callback);
777850

778851
return new self($array);
779852
}

src/Tempest/Support/tests/ArrayHelperTest.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,4 +1280,91 @@ public function test_pull(): void
12801280
],
12811281
);
12821282
}
1283+
1284+
public function test_sort(): void
1285+
{
1286+
$array = arr([1 => 'c', 2 => 'a', 3 => 'b']);
1287+
1288+
// Test auto-detects key preservation
1289+
$this->assertSame(
1290+
expected: ['a', 'b', 'c'],
1291+
actual: arr(['c', 'a', 'b'])->sort()->toArray(),
1292+
);
1293+
$this->assertSame(
1294+
expected: [2 => 'a', 3 => 'b', 1 => 'c'],
1295+
actual: $array->sort()->toArray(),
1296+
);
1297+
1298+
$this->assertSame(
1299+
expected: ['a', 'b', 'c'],
1300+
actual: $array->sort(desc: false, preserveKeys: false)->toArray(),
1301+
);
1302+
$this->assertSame(
1303+
expected: ['c', 'b', 'a'],
1304+
actual: $array->sort(desc: true, preserveKeys: false)->toArray(),
1305+
);
1306+
1307+
$this->assertSame(
1308+
expected: [2 => 'a', 3 => 'b', 1 => 'c'],
1309+
actual: $array->sort(desc: false, preserveKeys: true)->toArray(),
1310+
);
1311+
$this->assertSame(
1312+
expected: [1 => 'c', 3 => 'b', 2 => 'a'],
1313+
actual: $array->sort(desc: true, preserveKeys: true)->toArray(),
1314+
);
1315+
}
1316+
1317+
public function test_sort_by_callback(): void
1318+
{
1319+
$array = arr([1 => 'c', 2 => 'a', 3 => 'b']);
1320+
1321+
// Test auto-detects key preservation
1322+
$this->assertSame(
1323+
expected: ['a', 'b', 'c'],
1324+
actual: arr(['c', 'a', 'b'])->sortByCallback(fn ($a, $b) => $a <=> $b)->toArray(),
1325+
);
1326+
$this->assertSame(
1327+
expected: [2 => 'a', 3 => 'b', 1 => 'c'],
1328+
actual: $array->sortByCallback(fn ($a, $b) => $a <=> $b)->toArray(),
1329+
);
1330+
1331+
$this->assertSame(
1332+
expected: ['a', 'b', 'c'],
1333+
actual: $array->sortByCallback(
1334+
callback: fn ($a, $b) => $a <=> $b,
1335+
preserveKeys: false,
1336+
)->toArray(),
1337+
);
1338+
$this->assertSame(
1339+
expected: [2 => 'a', 3 => 'b', 1 => 'c'],
1340+
actual: $array->sortByCallback(
1341+
callback: fn ($a, $b) => $a <=> $b,
1342+
preserveKeys: true,
1343+
)->toArray(),
1344+
);
1345+
}
1346+
1347+
public function test_sort_keys(): void
1348+
{
1349+
$array = arr([2 => 'a', 1 => 'c', 3 => 'b']);
1350+
1351+
$this->assertSame(
1352+
expected: [1 => 'c', 2 => 'a', 3 => 'b'],
1353+
actual: $array->sortKeys(desc: false)->toArray(),
1354+
);
1355+
$this->assertSame(
1356+
expected: [3 => 'b', 2 => 'a', 1 => 'c'],
1357+
actual: $array->sortKeys(desc: true)->toArray(),
1358+
);
1359+
}
1360+
1361+
public function test_sort_keys_by_callback(): void
1362+
{
1363+
$array = arr([2 => 'a', 1 => 'c', 3 => 'b']);
1364+
1365+
$this->assertSame(
1366+
expected: [1 => 'c', 2 => 'a', 3 => 'b'],
1367+
actual: $array->sortKeysByCallback(fn ($a, $b) => $a <=> $b)->toArray(),
1368+
);
1369+
}
12831370
}

0 commit comments

Comments
 (0)