Skip to content

Commit 3448046

Browse files
authored
Merge pull request #42 from wiz-develop:claude/issue-40-20250716-0440
feat: Add filterStrict() and flatten() methods to ArrayList
2 parents 7fee997 + 8e1da55 commit 3448046

File tree

6 files changed

+125
-85
lines changed

6 files changed

+125
-85
lines changed

.github/workflows/claude-code-review.yml

Lines changed: 0 additions & 78 deletions
This file was deleted.

.github/workflows/phpstan.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,4 @@ jobs:
6868
key: "phpstan-result-cache-${{ github.run_id }}"
6969

7070
- name: Run PHPUnit tests
71-
run: vendor/bin/phpunit --configuration=phpunit.xml.dist --testdox --colors=always
71+
run: php -d zend.assertions=1 vendor/bin/phpunit --configuration=phpunit.xml.dist --testdox --colors=always

src/Collection/ArrayList.php

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ final public function firstOrFail(?Closure $closure = null)
253253
#[Override]
254254
final public function sole(?Closure $closure = null)
255255
{
256-
$items = $closure === null ? new static($this->elements) : $this->filter($closure);
256+
$items = $closure === null ? new static($this->elements) : $this->filterStrict($closure);
257257
$count = $items->count();
258258

259259
if ($count === 0) {
@@ -337,17 +337,47 @@ final public function mapStrict(Closure $closure): static
337337
return new static(array_map($closure, $this->elements, $keys));
338338
}
339339

340+
/**
341+
* @template TFlatMapValue
342+
* @param Closure(TValue,int): iterable<TFlatMapValue> $closure
343+
* @return self<TFlatMapValue>
344+
*/
345+
#[Override]
346+
final public function flatMap(Closure $closure): self
347+
{
348+
$result = [];
349+
350+
foreach ($this->elements as $index => $item) {
351+
$mapped = $closure($item, $index);
352+
353+
foreach ($mapped as $subItem) {
354+
$result[] = $subItem;
355+
}
356+
}
357+
358+
return new self($result);
359+
}
360+
361+
/**
362+
* @param Closure(TValue,int): bool $closure
363+
* @return self<TValue>
364+
*/
340365
#[Override]
341-
final public function filter(Closure $closure): static
366+
final public function filter(Closure $closure): self
342367
{
368+
return new self(array_filter($this->elements, $closure, ARRAY_FILTER_USE_BOTH));
369+
}
343370

371+
#[Override]
372+
final public function filterStrict(Closure $closure): static
373+
{
344374
return new static(array_filter($this->elements, $closure, ARRAY_FILTER_USE_BOTH));
345375
}
346376

347377
#[Override]
348378
final public function reject(Closure $closure): static
349379
{
350-
return $this->filter(static fn ($value, $key) => !$closure($value, $key));
380+
return $this->filterStrict(static fn ($value, $key) => !$closure($value, $key));
351381
}
352382

353383
#[Override]

src/Collection/List/IArrayList.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ public function merge(self $other): self;
125125
*/
126126
public function map(Closure $closure): self;
127127

128+
/**
129+
* 各要素に関数を適用し、結果を平坦化したコレクションを返す
130+
* @template TFlatMapValue
131+
* @param Closure(TValue,int): iterable<TFlatMapValue> $closure
132+
* @return self<TFlatMapValue>
133+
*/
134+
public function flatMap(Closure $closure): self;
135+
128136
/**
129137
* @param Closure(TValue,int): TValue $closure
130138
* @return static<TValue>
@@ -134,9 +142,17 @@ public function mapStrict(Closure $closure): static;
134142
/**
135143
* 与えられた真理判定に合格するすべての要素のコレクションを作成する。
136144
* @param Closure(TValue,int): bool $closure
145+
* @return self<TValue>
146+
*/
147+
public function filter(Closure $closure): self;
148+
149+
/**
150+
* 与えられた真理判定に合格するすべての要素のコレクションを作成する。
151+
* (strict version - 正確な型を保持)
152+
* @param Closure(TValue,int): bool $closure
137153
* @return static<TValue>
138154
*/
139-
public function filter(Closure $closure): static;
155+
public function filterStrict(Closure $closure): static;
140156

141157
/**
142158
* 与えられた真理判定に合格しないすべての要素のコレクションを作成する。

src/ValueObjectList.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function has(IValueObject $element): bool
2727
*/
2828
public function remove(IValueObject $element): static
2929
{
30-
return $this->filter(static fn (IValueObject $e) => !$e->equals($element));
30+
return $this->filterStrict(static fn (IValueObject $e) => !$e->equals($element));
3131
}
3232

3333
/**
@@ -45,6 +45,6 @@ public function put(IValueObject $element): static
4545
*/
4646
public function diff(self $other): static
4747
{
48-
return $this->filter(static fn (IValueObject $e) => !$other->has($e));
48+
return $this->filterStrict(static fn (IValueObject $e) => !$other->has($e));
4949
}
5050
}

tests/Unit/Collection/ArrayListTest.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,4 +467,76 @@ public function sort関数で要素をソートしたコレクションが取得
467467
// 元のコレクションは変更されない(イミュータブル)
468468
$this->assertEquals([3, 1, 4, 2, 5], $collection->toArray());
469469
}
470+
471+
#[Test]
472+
public function filter関数でselfを返すことができる(): void
473+
{
474+
$collection = ArrayList::from([1, 2, 3, 4, 5]);
475+
476+
$filtered = $collection->filter(static fn ($value) => $value % 2 === 0);
477+
478+
// 戻り値がArrayListインスタンス(self)であることを確認
479+
$this->assertInstanceOf(ArrayList::class, $filtered);
480+
$this->assertEquals([1 => 2, 3 => 4], $filtered->toArray());
481+
482+
// 元のコレクションは変更されない(イミュータブル)
483+
$this->assertEquals([1, 2, 3, 4, 5], $collection->toArray());
484+
}
485+
486+
#[Test]
487+
public function filterStrict関数でstaticを返すことができる(): void
488+
{
489+
$collection = ArrayList::from([1, 2, 3, 4, 5]);
490+
491+
$filtered = $collection->filterStrict(static fn ($value) => $value % 2 === 0);
492+
493+
// 戻り値が正確な型(static)であることを確認
494+
$this->assertInstanceOf(ArrayList::class, $filtered);
495+
$this->assertEquals([1 => 2, 3 => 4], $filtered->toArray());
496+
497+
// 元のコレクションは変更されない(イミュータブル)
498+
$this->assertEquals([1, 2, 3, 4, 5], $collection->toArray());
499+
}
500+
501+
#[Test]
502+
public function flatMap関数で各要素を変換して平坦化できる(): void
503+
{
504+
// 基本的な変換(各数値を2倍にして配列に包む)
505+
$collection = ArrayList::from([1, 2, 3]);
506+
$mapped = $collection->flatMap(static fn ($value) => [$value * 2]);
507+
508+
$this->assertInstanceOf(ArrayList::class, $mapped);
509+
$this->assertEquals([2, 4, 6], $mapped->toArray());
510+
511+
// 各要素を複数の要素に展開
512+
$collection2 = ArrayList::from([1, 2, 3]);
513+
$expanded = $collection2->flatMap(static fn ($value) => [$value, $value * 10]);
514+
515+
$this->assertEquals([1, 10, 2, 20, 3, 30], $expanded->toArray());
516+
517+
// 空の配列を返す場合
518+
$collection3 = ArrayList::from([1, 2, 3]);
519+
$filtered = $collection3->flatMap(static fn ($value) => $value % 2 === 0 ? [$value] : []);
520+
521+
$this->assertEquals([2], $filtered->toArray());
522+
523+
// 2次元配列の平坦化(従来のflattenと同等の動作)
524+
$collection4 = ArrayList::from([[1, 2], [3, 4], [5, 6]]);
525+
$flattened = $collection4->flatMap(static fn ($array) => $array);
526+
527+
$this->assertEquals([1, 2, 3, 4, 5, 6], $flattened->toArray());
528+
// 元のコレクションは変更されない(イミュータブル)
529+
$this->assertEquals([1, 2, 3], $collection->toArray());
530+
531+
// objectの2次元配列の平坦化(従来のflattenと同等の動作)
532+
$collection5 = ArrayList::from([
533+
ArrayList::from([1, 2]),
534+
ArrayList::from([3, 4]),
535+
ArrayList::from([5, 6]),
536+
]);
537+
$flattenedObjects = $collection5->flatMap(static fn ($array) => $array);
538+
$this->assertEquals([1, 2, 3, 4, 5, 6], $flattenedObjects->toArray());
539+
// 元のコレクションは変更されない(イミュータブル)
540+
$this->assertEquals([ArrayList::from([1, 2]), ArrayList::from([3, 4]), ArrayList::from([5, 6])], $collection5->toArray());
541+
}
470542
}

0 commit comments

Comments
 (0)