diff --git a/README.md b/README.md index eb9e32b..22e621e 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,8 @@ All entry points always return an instance of the pipeline. | `flip()` | Swaps keys and values. | `array_flip` | | `max()` | Finds the highest value. | `max` | | `min()` | Finds the lowest value. | `min` | +| `count()` | Counts value. | `array_count` | +| `runningCount()` | Counts seen values using a reference argument. | | | `toArray()` | Returns an array with all values. Eagerly executed. | `dict`, `ToDictionary` | | `toArrayPreservingKeys()` | Returns an array with all values and keys. Eagerly executed. | | | `runningVariance()` | Computes online statistics: sample mean, sample variance, standard deviation. | [Welford's method](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm) | diff --git a/src/Standard.php b/src/Standard.php index d9fda55..ccc3e36 100644 --- a/src/Standard.php +++ b/src/Standard.php @@ -547,6 +547,29 @@ public function toArrayPreservingKeys(): array return $this->toArray(true); } + /** + * Counts seen values online. + * + * @param ?int &$count the current count; initialized unless provided + * + * @param-out int $count + * + * @return $this + */ + public function runningCount( + ?int &$count + ): self { + $count ??= 0; + + $this->cast(static function ($input) use (&$count) { + ++$count; + + return $input; + }); + + return $this; + } + /** * {@inheritdoc} * diff --git a/tests/CountTest.php b/tests/CountTest.php index 62d2aeb..8d31317 100644 --- a/tests/CountTest.php +++ b/tests/CountTest.php @@ -25,6 +25,7 @@ use function Pipeline\fromArray; use function Pipeline\map; use function Pipeline\take; +use function range; /** * @covers \Pipeline\Standard @@ -61,4 +62,23 @@ public function testCountValues(): void yield 2 => 3; })); } + + public function testRunningCount(): void + { + $countEven = 1; + + $pipeline = map(fn () => yield from range(0, 100)) + ->runningCount($countAll) + ->filter(fn (int $n) => $n % 2) + ->runningCount($countEven) + ->filter(fn (int $n) => $n % 3); + + $this->assertSame(0, $countAll); + $this->assertSame(1, $countEven); + + $this->assertSame(33, $pipeline->count()); + + $this->assertSame(101, $countAll); + $this->assertSame(50, $countEven - 1); + } }