Skip to content

Commit a295bff

Browse files
authored
Merge pull request #270 from boesing/feature/multiple-groups
Allow items to be in multiple groups
2 parents e6cc708 + 62d7ffa commit a295bff

6 files changed

+60
-32
lines changed

src/Map.php

+15-14
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use function array_values;
2121
use function asort;
2222
use function implode;
23+
use function is_array;
2324
use function sprintf;
2425
use function strcmp;
2526
use function uasort;
@@ -375,16 +376,10 @@ public function partition(callable $callback): array
375376
return [$instance1, $instance2];
376377
}
377378

378-
/**
379-
* @template TGroup of non-empty-string
380-
* @psalm-param callable(TValue):TGroup $callback
381-
*
382-
* @psalm-return MapInterface<TGroup,MapInterface<TKey,TValue>>
383-
*/
384379
public function group(callable $callback): MapInterface
385380
{
386381
/**
387-
* @psalm-var MapInterface<TGroup,MapInterface<TKey,TValue>> $groups
382+
* @psalm-var MapInterface<non-empty-string,MapInterface<TKey,TValue>> $groups
388383
*/
389384
$groups = new GenericMap([]);
390385

@@ -393,15 +388,21 @@ public function group(callable $callback): MapInterface
393388
* @psalm-suppress ImpureFunctionCall Upstream projects have to ensure that they do not manipulate the
394389
* value here.
395390
*/
396-
$groupIdentifier = $callback($value);
397-
try {
398-
$group = $groups->get($groupIdentifier);
399-
} catch (OutOfBoundsException) {
400-
$group = clone $this;
401-
$group->data = [];
391+
$groupIdentifiers = $callback($value);
392+
if (! is_array($groupIdentifiers)) {
393+
$groupIdentifiers = [$groupIdentifiers];
402394
}
403395

404-
$groups = $groups->put($groupIdentifier, $group->put($key, $value));
396+
foreach ($groupIdentifiers as $groupIdentifier) {
397+
try {
398+
$group = $groups->get($groupIdentifier);
399+
} catch (OutOfBoundsException) {
400+
$group = clone $this;
401+
$group->data = [];
402+
}
403+
404+
$groups = $groups->put($groupIdentifier, $group->put($key, $value));
405+
}
405406
}
406407

407408
return $groups;

src/MapInterface.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,10 @@ public function partition(callable $callback): array;
215215
/**
216216
* Groups the items of this object by using the callback.
217217
*
218-
* @template TGroup of non-empty-string
218+
* @template TGroup of non-empty-string|non-empty-list<non-empty-string>
219219
* @psalm-param callable(TValue):TGroup $callback
220220
*
221-
* @psalm-return MapInterface<TGroup,MapInterface<TKey,TValue>>
221+
* @psalm-return MapInterface<non-empty-string,MapInterface<TKey,TValue>>
222222
*/
223223
public function group(callable $callback): MapInterface;
224224

src/OrderedList.php

+15-14
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use function assert;
2323
use function hash;
2424
use function implode;
25+
use function is_array;
2526
use function is_callable;
2627
use function serialize;
2728
use function sort;
@@ -367,30 +368,30 @@ public function partition(callable $callback): array
367368
return [$instance1, $instance2];
368369
}
369370

370-
/**
371-
* @template TGroup of non-empty-string
372-
* @psalm-param callable(TValue):TGroup $callback
373-
*
374-
* @psalm-return MapInterface<TGroup,OrderedListInterface<TValue>>
375-
*/
376371
public function group(callable $callback): MapInterface
377372
{
378-
/** @var MapInterface<TGroup,OrderedListInterface<TValue>> $groups */
373+
/** @var MapInterface<non-empty-string,OrderedListInterface<TValue>> $groups */
379374
$groups = new GenericMap([]);
380375
foreach ($this as $value) {
381376
/**
382377
* @psalm-suppress ImpureFunctionCall Upstream projects have to ensure that they do not manipulate the
383378
* value here.
384379
*/
385-
$groupName = $callback($value);
386-
if (! $groups->has($groupName)) {
387-
$groups = $groups->put($groupName, new GenericOrderedList([$value]));
388-
continue;
380+
$groupNames = $callback($value);
381+
if (! is_array($groupNames)) {
382+
$groupNames = [$groupNames];
389383
}
390384

391-
$existingGroup = $groups->get($groupName);
392-
$existingGroup = $existingGroup->add($value);
393-
$groups = $groups->put($groupName, $existingGroup);
385+
foreach ($groupNames as $groupName) {
386+
if (! $groups->has($groupName)) {
387+
$groups = $groups->put($groupName, new GenericOrderedList([$value]));
388+
continue;
389+
}
390+
391+
$existingGroup = $groups->get($groupName);
392+
$existingGroup = $existingGroup->add($value);
393+
$groups = $groups->put($groupName, $existingGroup);
394+
}
394395
}
395396

396397
return $groups;

src/OrderedListInterface.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,10 @@ public function partition(callable $callback): array;
182182
/**
183183
* Groups the items by using the callback.
184184
*
185-
* @template TGroup of non-empty-string
185+
* @template TGroup of non-empty-string|non-empty-list<non-empty-string>
186186
* @psalm-param callable(TValue):TGroup $callback
187187
*
188-
* @psalm-return MapInterface<TGroup,OrderedListInterface<TValue>>
188+
* @psalm-return MapInterface<non-empty-string,OrderedListInterface<TValue>>
189189
*/
190190
public function group(callable $callback): MapInterface;
191191

tests/GenericMapTest.php

+13
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,19 @@ public function testWillGroupValuesToNewInstancesOfInitialInstance(): void
736736
self::assertEquals($object2, $b->get('bar'));
737737
}
738738

739+
public function testWillGroupValueIntoMultipleGroups(): void
740+
{
741+
$map = new GenericMap([
742+
'foo' => $object1 = new GenericObject(1),
743+
]);
744+
745+
$grouped = $map->group(fn () => ['a', 'b']);
746+
self::assertTrue($grouped->has('a'));
747+
self::assertTrue($grouped->has('b'));
748+
self::assertTrue($grouped->get('a')->contains($object1));
749+
self::assertTrue($grouped->get('b')->contains($object1));
750+
}
751+
739752
/**
740753
* @template T
741754
* @psalm-param array<string,T> $elements

tests/GenericOrderedListTest.php

+13
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,19 @@ public function testWillGroupValuesToNewInstancesOfInitialInstance(): void
10481048
self::assertEquals($object2, $b->at(0));
10491049
}
10501050

1051+
public function testWillGroupValueIntoMultipleGroups(): void
1052+
{
1053+
$list = new GenericOrderedList([
1054+
$object1 = new GenericObject(1),
1055+
]);
1056+
1057+
$grouped = $list->group(fn () => ['a', 'b']);
1058+
self::assertTrue($grouped->has('a'));
1059+
self::assertTrue($grouped->has('b'));
1060+
self::assertTrue($grouped->get('a')->contains($object1));
1061+
self::assertTrue($grouped->get('b')->contains($object1));
1062+
}
1063+
10511064
/**
10521065
* @template T
10531066
* @psalm-param list<T> $data

0 commit comments

Comments
 (0)