Skip to content

Commit 6eb4027

Browse files
authored
Merge pull request #53 from wiz-develop:endou-mame/issue52
ArrayList, Map に filterAs 関数を追加(ついでに ArrayList に values 関数も実装)
2 parents 17d92fc + 158c82b commit 6eb4027

File tree

6 files changed

+236
-105
lines changed

6 files changed

+236
-105
lines changed

src/Collection/ArrayList.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,31 @@ final public function filter(Closure $closure): self
368368
return new self(array_filter($this->elements, $closure, ARRAY_FILTER_USE_BOTH));
369369
}
370370

371+
/**
372+
* @template TFilterValue of TValue
373+
* @param class-string<TFilterValue> $innerClass
374+
* @return self<TFilterValue>
375+
*/
376+
#[Override]
377+
final public function filterAs(string $innerClass): self
378+
{
379+
// @phpstan-ignore-next-line
380+
return new self(array_filter(
381+
$this->elements,
382+
static fn ($value) => $value instanceof $innerClass,
383+
ARRAY_FILTER_USE_BOTH,
384+
));
385+
}
386+
387+
/**
388+
* @return self<TValue>
389+
*/
390+
#[Override]
391+
final public function values(): self
392+
{
393+
return new self(array_values($this->elements));
394+
}
395+
371396
#[Override]
372397
final public function filterStrict(Closure $closure): static
373398
{

src/Collection/List/IArrayList.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,21 @@ public function mapStrict(Closure $closure): static;
146146
*/
147147
public function filter(Closure $closure): self;
148148

149+
/**
150+
* 与えられたクラスのインスタンスのみを含むコレクションを作成する。
151+
*
152+
* @template TFilterValue of TValue
153+
* @param class-string<TFilterValue> $innerClass
154+
* @return self<TFilterValue>
155+
*/
156+
public function filterAs(string $innerClass): self;
157+
158+
/**
159+
* キーが連続した整数にリセットされた新しいコレクションを作成する。
160+
* @return self<TValue>
161+
*/
162+
public function values(): self;
163+
149164
/**
150165
* 与えられた真理判定に合格するすべての要素のコレクションを作成する。
151166
* (strict version - 正確な型を保持)

src/Collection/Map.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ final public function offsetSet($offset, $value): void
8383
}
8484

8585
/**
86+
* @return TValue
8687
* @throws OutOfBoundsException
8788
*/
8889
#[Override]
@@ -433,6 +434,26 @@ final public function filter(Closure $closure): static
433434
return new static($elements);
434435
}
435436

437+
/**
438+
* @template TFilterValue of TValue
439+
* @param class-string<TFilterValue> $innerClass
440+
* @return static<TKey,TFilterValue>
441+
*/
442+
#[Override]
443+
final public function filterAs(string $innerClass): static
444+
{
445+
/** @var array<int,Pair<TKey,TFilterValue>> */
446+
$elements = [];
447+
448+
foreach ($this->elements as $index => $pair) {
449+
if ($pair->value instanceof $innerClass) {
450+
$elements[$index] = Pair::of($pair->key, $pair->value);
451+
}
452+
}
453+
454+
return new static($elements); // @phpstan-ignore-line
455+
}
456+
436457
#[Override]
437458
final public function reject(Closure $closure): static
438459
{

src/Collection/Map/IMap.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,15 @@ public function mapStrict(Closure $closure): static;
155155
*/
156156
public function filter(Closure $closure): static;
157157

158+
/**
159+
* 与えられたクラスのインスタンスのみを含むコレクションを作成する。
160+
*
161+
* @template TFilterValue of TValue
162+
* @param class-string<TFilterValue> $innerClass
163+
* @return static<TKey,TFilterValue>
164+
*/
165+
public function filterAs(string $innerClass): static;
166+
158167
/**
159168
* 与えられた真理判定に合格しないすべての要素のコレクションを作成する。
160169
* @param Closure(TValue,TKey): bool $closure

tests/Unit/Collection/ArrayListTest.php

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,35 @@
2222
final class ArrayListTest extends TestCase
2323
{
2424
/**
25-
* @return array<string, array{array<mixed>}>
25+
* @param array<int,mixed> $elements
2626
*/
27-
public static function 様々な要素のコレクションを提供(): array
27+
#[Test]
28+
#[DataProvider('様々な要素のコレクションを提供')]
29+
public function from静的メソッドでインスタンスが作成できる(array $elements): void
2830
{
29-
return [
30-
'プリミティブ値の配列' => [[1, 2, 3, 4, 5]],
31-
'文字列の配列' => [['apple', 'banana', 'cherry']],
32-
'空の配列' => [[]],
33-
'混合型の配列' => [[1, 'string', true, 3.14]],
34-
];
31+
$collection = ArrayList::from($elements);
32+
33+
$this->assertInstanceOf(ArrayList::class, $collection);
34+
$this->assertEquals($elements, $collection->toArray());
35+
}
36+
37+
/**
38+
* @param array<int,mixed> $elements
39+
*/
40+
#[Test]
41+
#[DataProvider('provide独自クラスのコレクションが作成できるCases')]
42+
public function 独自クラスのコレクションが作成できる(array $elements): void
43+
{
44+
$collection = ArrayList::from($elements);
45+
46+
$this->assertInstanceOf(ArrayList::class, $collection);
47+
$this->assertEquals($elements, $collection->toArray());
3548
}
3649

3750
/**
3851
* @return array<string, array{array<mixed>}>
3952
*/
40-
public static function 独自クラスを含むコレクションを提供(): array
53+
public static function provide独自クラスのコレクションが作成できるCases(): iterable
4154
{
4255
return [
4356
'StringValue配列' => [[
@@ -63,32 +76,6 @@ public static function 独自クラスを含むコレクションを提供(): ar
6376
];
6477
}
6578

66-
/**
67-
* @param array<int,mixed> $elements
68-
*/
69-
#[Test]
70-
#[DataProvider('様々な要素のコレクションを提供')]
71-
public function from静的メソッドでインスタンスが作成できる(array $elements): void
72-
{
73-
$collection = ArrayList::from($elements);
74-
75-
$this->assertInstanceOf(ArrayList::class, $collection);
76-
$this->assertEquals($elements, $collection->toArray());
77-
}
78-
79-
/**
80-
* @param array<int,mixed> $elements
81-
*/
82-
#[Test]
83-
#[DataProvider('独自クラスを含むコレクションを提供')]
84-
public function 独自クラスのコレクションが作成できる(array $elements): void
85-
{
86-
$collection = ArrayList::from($elements);
87-
88-
$this->assertInstanceOf(ArrayList::class, $collection);
89-
$this->assertEquals($elements, $collection->toArray());
90-
}
91-
9279
#[Test]
9380
public function empty静的メソッドで空のコレクションが作成できる(): void
9481
{
@@ -137,6 +124,19 @@ public function tryFrom静的メソッドで有効な配列から成功結果が
137124
$this->assertEquals($elements, $collection->toArray());
138125
}
139126

127+
/**
128+
* @return array<string, array{array<mixed>}>
129+
*/
130+
public static function 様々な要素のコレクションを提供(): iterable
131+
{
132+
return [
133+
'プリミティブ値の配列' => [[1, 2, 3, 4, 5]],
134+
'文字列の配列' => [['apple', 'banana', 'cherry']],
135+
'空の配列' => [[]],
136+
'混合型の配列' => [[1, 'string', true, 3.14]],
137+
];
138+
}
139+
140140
#[Test]
141141
public function first関数で先頭要素が取得できる(): void
142142
{
@@ -539,4 +539,42 @@ public function flatMap関数で各要素を変換して平坦化できる(): vo
539539
// 元のコレクションは変更されない(イミュータブル)
540540
$this->assertEquals([ArrayList::from([1, 2]), ArrayList::from([3, 4]), ArrayList::from([5, 6])], $collection5->toArray());
541541
}
542+
543+
#[Test]
544+
public function filterAs関数で特定のクラスのインスタンスのみを含むコレクションが取得できる(): void
545+
{
546+
$collection = ArrayList::from([
547+
StringValue::from('apple'),
548+
IntegerValue::from(10),
549+
StringValue::from('banana'),
550+
DecimalValue::from(new Number('2.5')),
551+
]);
552+
553+
$filtered = $collection
554+
->filterAs(StringValue::class)
555+
->values();
556+
557+
// @phpstan-ignore-next-line
558+
$this->assertContainsOnlyInstancesOf(StringValue::class, $filtered);
559+
560+
$this->assertCount(2, $filtered);
561+
$this->assertEquals('apple', $filtered[0]->value);
562+
$this->assertEquals('banana', $filtered[1]->value);
563+
}
564+
565+
#[Test]
566+
public function values関数でキーが連続した整数にリセットされた新しいコレクションが取得できる(): void
567+
{
568+
$collection = ArrayList::from([10, 20, 30]);
569+
570+
$filteredCollection = $collection->filter(static fn ($x) => $x >= 20);
571+
$this->assertCount(2, $filteredCollection);
572+
$this->assertEquals($filteredCollection[1], 20);
573+
$this->assertEquals($filteredCollection[2], 30);
574+
575+
$valuesCollection = $filteredCollection->values();
576+
$this->assertCount(2, $valuesCollection);
577+
$this->assertEquals($valuesCollection[0], 20);
578+
$this->assertEquals($valuesCollection[1], 30);
579+
}
542580
}

0 commit comments

Comments
 (0)