Skip to content

Commit

Permalink
feat(support): add sorting methods to ArrayHelper (#659)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bapawe authored Nov 6, 2024
1 parent 32bf4d0 commit 8f52e4a
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 3 deletions.
79 changes: 76 additions & 3 deletions src/Tempest/Support/src/ArrayHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -768,12 +768,85 @@ public function mapTo(string $to): self
}

/**
* Sorts the array in ascending order.
* Returns a new instance of this array sorted by its values.
*
* @param bool $desc Sorts in descending order if `true`; defaults to `false` (ascending).
* @param bool|null $preserveKeys Preserves array keys if `true`; reindexes numerically if `false`.
* Defaults to `null`, which auto-detects preservation based on array type (associative or list).
* @param int $flags Sorting flags to define comparison behavior, defaulting to `SORT_REGULAR`.
* @return self<array-key, TValue> Key type depends on whether array keys are preserved or not.
*/
public function sort(bool $desc = false, ?bool $preserveKeys = null, int $flags = SORT_REGULAR): self
{
$array = $this->array;

if ($preserveKeys === null) {
$preserveKeys = $this->isAssoc();
}

if ($preserveKeys) {
$desc ? arsort($array, $flags) : asort($array, $flags);
} else {
$desc ? rsort($array, $flags) : sort($array, $flags);
}

return new self($array);
}

/**
* Returns a new instance of this array sorted by its values using a callback function.
*
* @param callable $callback The function to use for comparing values. It should accept two parameters
* and return an integer less than, equal to, or greater than zero if the
* first argument is considered to be respectively less than, equal to, or
* greater than the second.
* @param bool|null $preserveKeys Preserves array keys if `true`; reindexes numerically if `false`.
* Defaults to `null`, which auto-detects preservation based on array type (associative or list).
* @return self<array-key, TValue> Key type depends on whether array keys are preserved or not.
*/
public function sortByCallback(callable $callback, ?bool $preserveKeys = null): self
{
$array = $this->array;

if ($preserveKeys === null) {
$preserveKeys = $this->isAssoc();
}

$preserveKeys ? uasort($array, $callback) : usort($array, $callback);

return new self($array);
}

/**
* Returns a new instance of this array sorted by its keys.
*
* @param bool $desc Sorts in descending order if `true`; defaults to `false` (ascending).
* @param int $flags Sorting flags to define comparison behavior, defaulting to `SORT_REGULAR`.
* @return self<TKey, TValue>
*/
public function sortKeys(bool $desc = false, int $flags = SORT_REGULAR): self
{
$array = $this->array;

$desc ? krsort($array, $flags) : ksort($array, $flags);

return new self($array);
}

/**
* Returns a new instance of this array sorted by its keys using a callback function.
*
* @param callable $callback The function to use for comparing keys. It should accept two parameters
* and return an integer less than, equal to, or greater than zero if the
* first argument is considered to be respectively less than, equal to, or
* greater than the second.
* @return self<TKey, TValue>
*/
public function sort(): self
public function sortKeysByCallback(callable $callback): self
{
$array = $this->array;
sort($array);

uksort($array, $callback);

return new self($array);
}
Expand Down
87 changes: 87 additions & 0 deletions src/Tempest/Support/tests/ArrayHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1280,4 +1280,91 @@ public function test_pull(): void
],
);
}

public function test_sort(): void
{
$array = arr([1 => 'c', 2 => 'a', 3 => 'b']);

// Test auto-detects key preservation
$this->assertSame(
expected: ['a', 'b', 'c'],
actual: arr(['c', 'a', 'b'])->sort()->toArray(),
);
$this->assertSame(
expected: [2 => 'a', 3 => 'b', 1 => 'c'],
actual: $array->sort()->toArray(),
);

$this->assertSame(
expected: ['a', 'b', 'c'],
actual: $array->sort(desc: false, preserveKeys: false)->toArray(),
);
$this->assertSame(
expected: ['c', 'b', 'a'],
actual: $array->sort(desc: true, preserveKeys: false)->toArray(),
);

$this->assertSame(
expected: [2 => 'a', 3 => 'b', 1 => 'c'],
actual: $array->sort(desc: false, preserveKeys: true)->toArray(),
);
$this->assertSame(
expected: [1 => 'c', 3 => 'b', 2 => 'a'],
actual: $array->sort(desc: true, preserveKeys: true)->toArray(),
);
}

public function test_sort_by_callback(): void
{
$array = arr([1 => 'c', 2 => 'a', 3 => 'b']);

// Test auto-detects key preservation
$this->assertSame(
expected: ['a', 'b', 'c'],
actual: arr(['c', 'a', 'b'])->sortByCallback(fn ($a, $b) => $a <=> $b)->toArray(),
);
$this->assertSame(
expected: [2 => 'a', 3 => 'b', 1 => 'c'],
actual: $array->sortByCallback(fn ($a, $b) => $a <=> $b)->toArray(),
);

$this->assertSame(
expected: ['a', 'b', 'c'],
actual: $array->sortByCallback(
callback: fn ($a, $b) => $a <=> $b,
preserveKeys: false,
)->toArray(),
);
$this->assertSame(
expected: [2 => 'a', 3 => 'b', 1 => 'c'],
actual: $array->sortByCallback(
callback: fn ($a, $b) => $a <=> $b,
preserveKeys: true,
)->toArray(),
);
}

public function test_sort_keys(): void
{
$array = arr([2 => 'a', 1 => 'c', 3 => 'b']);

$this->assertSame(
expected: [1 => 'c', 2 => 'a', 3 => 'b'],
actual: $array->sortKeys(desc: false)->toArray(),
);
$this->assertSame(
expected: [3 => 'b', 2 => 'a', 1 => 'c'],
actual: $array->sortKeys(desc: true)->toArray(),
);
}

public function test_sort_keys_by_callback(): void
{
$array = arr([2 => 'a', 1 => 'c', 3 => 'b']);

$this->assertSame(
expected: [1 => 'c', 2 => 'a', 3 => 'b'],
actual: $array->sortKeysByCallback(fn ($a, $b) => $a <=> $b)->toArray(),
);
}
}

0 comments on commit 8f52e4a

Please # to comment.