Skip to content

Commit

Permalink
Merge pull request #15 from boesing/feature/grouping
Browse files Browse the repository at this point in the history
  • Loading branch information
boesing authored Nov 6, 2020
2 parents bbcee9f + 2cd6a29 commit 38ab698
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 2 deletions.
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"lcobucci/clock": "^1.2",
"phpunit/phpunit": "^9.2",
"psalm/plugin-phpunit": "^0.12.2",
"vimeo/psalm": "~3.16.0"
"vimeo/psalm": "^4.0"
},
"config": {
"preferred-install": "dist",
Expand All @@ -33,6 +33,7 @@
"prefer-stable": true,
"scripts": {
"cs-check": "phpcs",
"cs-fix": "phpcbf"
"cs-fix": "phpcbf",
"analyze": "vendor/bin/psalm --stats"
}
}
31 changes: 31 additions & 0 deletions src/Map.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Boesing\TypedArrays;

use Closure;
use OutOfBoundsException;

use function array_diff_ukey;
Expand Down Expand Up @@ -293,4 +294,34 @@ public function partition(callable $callback): array

return [$instance1, $instance2];
}

/**
* @template TGroup of non-empty-string
* @psalm-param Closure(TValue):TGroup $callback
*
* @psalm-return MapInterface<TGroup,MapInterface<TKey,TValue>>
*/
public function group(callable $callback): MapInterface
{
/**
* @psalm-var MapInterface<TGroup,MapInterface<TKey,TValue>> $groups
*/
$groups = new GenericMap([]);

foreach ($this->data as $key => $value) {
$groupIdentifier = $callback($value);
try {
/** @psalm-suppress ImpureMethodCall */
$group = $groups->get($groupIdentifier);
} catch (OutOfBoundsException $exception) {
$group = clone $this;
$group->data = [];
}

/** @psalm-suppress ImpureMethodCall */
$groups = $groups->put($groupIdentifier, $group->put($key, $value));
}

return $groups;
}
}
8 changes: 8 additions & 0 deletions src/MapInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,12 @@ public function has(string $key): bool;
* @psalm-return array{0:MapInterface<TKey,TValue>,1:MapInterface<TKey,TValue>}
*/
public function partition(callable $callback): array;

/**
* @template TGroup of non-empty-string
* @psalm-param Closure(TValue):TGroup $callback
*
* @psalm-return MapInterface<TGroup,MapInterface<TKey,TValue>>
*/
public function group(callable $callback): MapInterface;
}
28 changes: 28 additions & 0 deletions src/OrderedList.php
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,32 @@ public function partition(callable $callback): array

return [$instance1, $instance2];
}

/**
* @template TGroup of non-empty-string
* @psalm-param Closure(TValue):TGroup $callback
*
* @psalm-return MapInterface<TGroup,OrderedListInterface<TValue>>
*/
public function group(callable $callback): MapInterface
{
/** @var MapInterface<TGroup,OrderedListInterface<TValue>> $groups */
$groups = new GenericMap([]);
foreach ($this as $value) {
$groupName = $callback($value);
/** @psalm-suppress ImpureMethodCall */
if (! $groups->has($groupName)) {
$groups = $groups->put($groupName, new GenericOrderedList([$value]));
continue;
}

/** @psalm-suppress ImpureMethodCall */
$existingGroup = $groups->get($groupName);
$existingGroup = $existingGroup->add($value);
/** @psalm-suppress ImpureMethodCall */
$groups = $groups->put($groupName, $existingGroup);
}

return $groups;
}
}
8 changes: 8 additions & 0 deletions src/OrderedListInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,12 @@ public function find(callable $callback);
* @psalm-return array{0:OrderedListInterface<TValue>,1:OrderedListInterface<TValue>}
*/
public function partition(callable $callback): array;

/**
* @template TGroup of non-empty-string
* @psalm-param Closure(TValue):TGroup $callback
*
* @psalm-return MapInterface<TGroup,OrderedListInterface<TValue>>
*/
public function group(callable $callback): MapInterface;
}
22 changes: 22 additions & 0 deletions tests/GenericMapTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -603,4 +603,26 @@ static function (string $value): bool {
self::assertTrue($filtered->has('foo'));
self::assertEquals('bar', $filtered->get('foo'));
}

public function testWillGroupValuesToNewInstancesOfInitialInstance(): void
{
$map = new GenericMap([
'foo' => $object1 = new GenericObject(1),
'bar' => $object2 = new GenericObject(2),
]);

$grouped = $map->group(static function (GenericObject $object): string {
return $object->id % 2 ? 'a' : 'b';
});

self::assertTrue($grouped->has('a'));
self::assertTrue($grouped->has('b'));

$a = $grouped->get('a');
self::assertCount(1, $a);
self::assertEquals($object1, $a->get('foo'));
$b = $grouped->get('b');
self::assertCount(1, $b);
self::assertEquals($object2, $b->get('bar'));
}
}
24 changes: 24 additions & 0 deletions tests/GenericOrderedListTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -981,4 +981,28 @@ static function (string $value): bool {
['bar'],
];
}

public function testWillGroupValuesToNewInstancesOfInitialInstance(): void
{
$list = new GenericOrderedList([
$object1 = new GenericObject(1),
$object2 = new GenericObject(2),
$object3 = new GenericObject(3),
]);

$grouped = $list->group(static function (GenericObject $object): string {
return $object->id % 2 ? 'a' : 'b';
});

self::assertTrue($grouped->has('a'));
self::assertTrue($grouped->has('b'));

$a = $grouped->get('a');
self::assertCount(2, $a);
self::assertEquals($object1, $a->at(0));
self::assertEquals($object3, $a->at(1));
$b = $grouped->get('b');
self::assertCount(1, $b);
self::assertEquals($object2, $b->at(0));
}
}

0 comments on commit 38ab698

Please sign in to comment.