Skip to content

Commit d696826

Browse files
feat(support): add groupBy to array utils (#1047)
1 parent b2dfd32 commit d696826

File tree

4 files changed

+80
-0
lines changed

4 files changed

+80
-0
lines changed

src/Tempest/Support/src/Arr/ManipulatesArray.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,16 @@ public function join(string $glue = ', ', ?string $finalGlue = ' and '): Immutab
555555
return namespace\join($this->value, $glue, $finalGlue);
556556
}
557557

558+
/**
559+
* Groups the array by the results of the provided keyExtractor.
560+
*
561+
* @param Closure(TValue, TKey): array-key $keyExtractor
562+
*/
563+
public function groupBy(Closure $keyExtractor): static
564+
{
565+
return $this->createOrModify(namespace\group_by($this->value, $keyExtractor));
566+
}
567+
558568
/**
559569
* Flattens the instance to a single-level array, or until the specified `$depth` is reached.
560570
*

src/Tempest/Support/src/Arr/functions.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,51 @@ function flatten(iterable $array, int|float $depth = INF): array
932932
return $result;
933933
}
934934

935+
/**
936+
* Returns a copy of the array grouped by the result of the given `$keyExtractor`.
937+
* The keys of the resulting array are the values returned by the `$keyExtractor`.
938+
*
939+
* ### Example
940+
* ```php
941+
* group_by(
942+
* [
943+
* ['country' => 'france', 'continent' => 'europe'],
944+
* ['country' => 'Sweden', 'continent' => 'europe'],
945+
* ['country' => 'USA', 'continent' => 'america']
946+
* ],
947+
* fn($item) => $item['continent']
948+
* );
949+
* // [
950+
* // 'europe' => [
951+
* // ['country' => 'france', 'continent' => 'europe'],
952+
* // ['country' => 'Sweden', 'continent' => 'europe']
953+
* // ],
954+
* // 'america' => [
955+
* // ['country' => 'USA', 'continent' => 'america']
956+
* // ]
957+
* // ]
958+
* ```
959+
*
960+
* @template TKey of array-key
961+
* @template TValue
962+
* @param iterable<TKey,TValue> $array
963+
* @param Closure(TValue, TKey): array-key $keyExtracor
964+
*/
965+
function group_by(iterable $array, Closure $keyExtracor): array
966+
{
967+
$array = to_array($array);
968+
969+
$result = [];
970+
971+
foreach ($array as $key => $item) {
972+
$key = $keyExtracor($item, $key);
973+
974+
$result[$key][] = $item;
975+
}
976+
977+
return $result;
978+
}
979+
935980
/**
936981
* Returns a copy of the given array, with each item transformed by the given callback, then flattens it by the specified depth.
937982
*

src/Tempest/Support/tests/Arr/ManipulatesArrayTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,4 +1739,28 @@ public function test_dot(): void
17391739
->equals($array->dot()),
17401740
);
17411741
}
1742+
1743+
public function test_group_by(): void
1744+
{
1745+
$array = arr([
1746+
['brand' => 'brand1', 'model' => 'model1'],
1747+
['brand' => 'brand1', 'model' => 'model2'],
1748+
['brand' => 'brand2', 'model' => 'model3'],
1749+
['brand' => 'brand2', 'model' => 'model4'],
1750+
]);
1751+
1752+
$this->assertTrue(
1753+
arr([
1754+
'brand1' => [
1755+
['brand' => 'brand1', 'model' => 'model1'],
1756+
['brand' => 'brand1', 'model' => 'model2'],
1757+
],
1758+
'brand2' => [
1759+
['brand' => 'brand2', 'model' => 'model3'],
1760+
['brand' => 'brand2', 'model' => 'model4'],
1761+
],
1762+
])
1763+
->equals($array->groupBy(fn ($item) => $item['brand'])),
1764+
);
1765+
}
17421766
}

tests/Integration/Support/ArrayMutabilityTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ final class ArrayMutabilityTest extends TestCase
3131
'dump',
3232
'dd',
3333
'tap',
34+
'groupBy',
3435
];
3536

3637
public function test_immutable_array(): void

0 commit comments

Comments
 (0)