Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/Collection/ArrayList.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,31 @@ final public function filter(Closure $closure): self
return new self(array_filter($this->elements, $closure, ARRAY_FILTER_USE_BOTH));
}

/**
* @template TFilterValue of TValue
* @param class-string<TFilterValue> $innerClass
* @return self<TFilterValue>
*/
#[Override]
final public function filterAs(string $innerClass): self
{
// @phpstan-ignore-next-line
return new self(array_filter(
$this->elements,
static fn ($value) => $value instanceof $innerClass,
ARRAY_FILTER_USE_BOTH,
));
}

/**
* @return self<TValue>
*/
#[Override]
final public function values(): self
{
return new self(array_values($this->elements));
}

#[Override]
final public function filterStrict(Closure $closure): static
{
Expand Down
15 changes: 15 additions & 0 deletions src/Collection/List/IArrayList.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,21 @@ public function mapStrict(Closure $closure): static;
*/
public function filter(Closure $closure): self;

/**
* 与えられたクラスのインスタンスのみを含むコレクションを作成する。
*
* @template TFilterValue of TValue
* @param class-string<TFilterValue> $innerClass
* @return self<TFilterValue>
*/
public function filterAs(string $innerClass): self;

/**
* キーが連続した整数にリセットされた新しいコレクションを作成する。
* @return self<TValue>
*/
public function values(): self;

/**
* 与えられた真理判定に合格するすべての要素のコレクションを作成する。
* (strict version - 正確な型を保持)
Expand Down
21 changes: 21 additions & 0 deletions src/Collection/Map.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ final public function offsetSet($offset, $value): void
}

/**
* @return TValue
* @throws OutOfBoundsException
*/
#[Override]
Expand Down Expand Up @@ -433,6 +434,26 @@ final public function filter(Closure $closure): static
return new static($elements);
}

/**
* @template TFilterValue of TValue
* @param class-string<TFilterValue> $innerClass
* @return static<TKey,TFilterValue>
*/
#[Override]
final public function filterAs(string $innerClass): static
{
/** @var array<int,Pair<TKey,TFilterValue>> */
$elements = [];

foreach ($this->elements as $index => $pair) {
if ($pair->value instanceof $innerClass) {
$elements[$index] = Pair::of($pair->key, $pair->value);
}
}

return new static($elements); // @phpstan-ignore-line
}

#[Override]
final public function reject(Closure $closure): static
{
Expand Down
9 changes: 9 additions & 0 deletions src/Collection/Map/IMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,15 @@ public function mapStrict(Closure $closure): static;
*/
public function filter(Closure $closure): static;

/**
* 与えられたクラスのインスタンスのみを含むコレクションを作成する。
*
* @template TFilterValue of TValue
* @param class-string<TFilterValue> $innerClass
* @return static<TKey,TFilterValue>
*/
public function filterAs(string $innerClass): static;

/**
* 与えられた真理判定に合格しないすべての要素のコレクションを作成する。
* @param Closure(TValue,TKey): bool $closure
Expand Down
108 changes: 73 additions & 35 deletions tests/Unit/Collection/ArrayListTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,35 @@
final class ArrayListTest extends TestCase
{
/**
* @return array<string, array{array<mixed>}>
* @param array<int,mixed> $elements
*/
public static function 様々な要素のコレクションを提供(): array
#[Test]
#[DataProvider('様々な要素のコレクションを提供')]
public function from静的メソッドでインスタンスが作成できる(array $elements): void
{
return [
'プリミティブ値の配列' => [[1, 2, 3, 4, 5]],
'文字列の配列' => [['apple', 'banana', 'cherry']],
'空の配列' => [[]],
'混合型の配列' => [[1, 'string', true, 3.14]],
];
$collection = ArrayList::from($elements);

$this->assertInstanceOf(ArrayList::class, $collection);
$this->assertEquals($elements, $collection->toArray());
}

/**
* @param array<int,mixed> $elements
*/
#[Test]
#[DataProvider('provide独自クラスのコレクションが作成できるCases')]
public function 独自クラスのコレクションが作成できる(array $elements): void
{
$collection = ArrayList::from($elements);

$this->assertInstanceOf(ArrayList::class, $collection);
$this->assertEquals($elements, $collection->toArray());
}

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

/**
* @param array<int,mixed> $elements
*/
#[Test]
#[DataProvider('様々な要素のコレクションを提供')]
public function from静的メソッドでインスタンスが作成できる(array $elements): void
{
$collection = ArrayList::from($elements);

$this->assertInstanceOf(ArrayList::class, $collection);
$this->assertEquals($elements, $collection->toArray());
}

/**
* @param array<int,mixed> $elements
*/
#[Test]
#[DataProvider('独自クラスを含むコレクションを提供')]
public function 独自クラスのコレクションが作成できる(array $elements): void
{
$collection = ArrayList::from($elements);

$this->assertInstanceOf(ArrayList::class, $collection);
$this->assertEquals($elements, $collection->toArray());
}

#[Test]
public function empty静的メソッドで空のコレクションが作成できる(): void
{
Expand Down Expand Up @@ -137,6 +124,19 @@ public function tryFrom静的メソッドで有効な配列から成功結果が
$this->assertEquals($elements, $collection->toArray());
}

/**
* @return array<string, array{array<mixed>}>
*/
public static function 様々な要素のコレクションを提供(): iterable
{
return [
'プリミティブ値の配列' => [[1, 2, 3, 4, 5]],
'文字列の配列' => [['apple', 'banana', 'cherry']],
'空の配列' => [[]],
'混合型の配列' => [[1, 'string', true, 3.14]],
];
}

#[Test]
public function first関数で先頭要素が取得できる(): void
{
Expand Down Expand Up @@ -539,4 +539,42 @@ public function flatMap関数で各要素を変換して平坦化できる(): vo
// 元のコレクションは変更されない(イミュータブル)
$this->assertEquals([ArrayList::from([1, 2]), ArrayList::from([3, 4]), ArrayList::from([5, 6])], $collection5->toArray());
}

#[Test]
public function filterAs関数で特定のクラスのインスタンスのみを含むコレクションが取得できる(): void
{
$collection = ArrayList::from([
StringValue::from('apple'),
IntegerValue::from(10),
StringValue::from('banana'),
DecimalValue::from(new Number('2.5')),
]);

$filtered = $collection
->filterAs(StringValue::class)
->values();

// @phpstan-ignore-next-line
$this->assertContainsOnlyInstancesOf(StringValue::class, $filtered);

$this->assertCount(2, $filtered);
$this->assertEquals('apple', $filtered[0]->value);
$this->assertEquals('banana', $filtered[1]->value);
}

#[Test]
public function values関数でキーが連続した整数にリセットされた新しいコレクションが取得できる(): void
{
$collection = ArrayList::from([10, 20, 30]);

$filteredCollection = $collection->filter(static fn ($x) => $x >= 20);
$this->assertCount(2, $filteredCollection);
$this->assertEquals($filteredCollection[1], 20);
$this->assertEquals($filteredCollection[2], 30);

$valuesCollection = $filteredCollection->values();
$this->assertCount(2, $valuesCollection);
$this->assertEquals($valuesCollection[0], 20);
$this->assertEquals($valuesCollection[1], 30);
}
}
Loading
Loading