Skip to content

Commit 0e5c45c

Browse files
authored
Add runningCount (#127)
1 parent f5b16c8 commit 0e5c45c

File tree

3 files changed

+117
-0
lines changed

3 files changed

+117
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ All entry points always return an instance of the pipeline.
124124
| `flip()` | Swaps keys and values. | `array_flip` |
125125
| `max()` | Finds the highest value. | `max` |
126126
| `min()` | Finds the lowest value. | `min` |
127+
| `count()` | Counts values. Eagerly executed.| `array_count` |
128+
| `runningCount()` | Counts seen values using a reference argument. | |
127129
| `toArray()` | Returns an array with all values. Eagerly executed. | `dict`, `ToDictionary` |
128130
| `toArrayPreservingKeys()` | Returns an array with all values and keys. Eagerly executed. | |
129131
| `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) |

src/Standard.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,29 @@ public function toArrayPreservingKeys(): array
547547
return $this->toArray(true);
548548
}
549549

550+
/**
551+
* Counts seen values online.
552+
*
553+
* @param ?int &$count the current count; initialized unless provided
554+
*
555+
* @param-out int $count
556+
*
557+
* @return $this
558+
*/
559+
public function runningCount(
560+
?int &$count
561+
): self {
562+
$count ??= 0;
563+
564+
$this->cast(static function ($input) use (&$count) {
565+
++$count;
566+
567+
return $input;
568+
});
569+
570+
return $this;
571+
}
572+
550573
/**
551574
* {@inheritdoc}
552575
*

tests/RunningCountTest.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
/**
3+
* Copyright 2017, 2018 Alexey Kopytko <[email protected]>
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace Tests\Pipeline;
21+
22+
use PHPUnit\Framework\TestCase;
23+
use function Pipeline\map;
24+
use function Pipeline\take;
25+
use function range;
26+
27+
/**
28+
* @covers \Pipeline\Standard
29+
*
30+
* @internal
31+
*/
32+
final class RunningCountTest extends TestCase
33+
{
34+
public function testRunningCount(): void
35+
{
36+
$countEven = 1;
37+
38+
$pipeline = map(fn () => yield from range(0, 100))
39+
->runningCount($countAll)
40+
->filter(fn (int $n) => 0 === $n % 2)
41+
->runningCount($countEven)
42+
->filter(fn (int $n) => $n % 3);
43+
44+
$this->assertSame(0, $countAll);
45+
$this->assertSame(1, $countEven);
46+
47+
$this->assertSame(34, $pipeline->count());
48+
49+
$this->assertSame(101, $countAll);
50+
$this->assertSame(51, $countEven - 1);
51+
}
52+
53+
public function testRunningCountLazy(): void
54+
{
55+
$countEven = 1;
56+
57+
$pipeline = map(fn () => yield from range(0, 100))
58+
->runningCount($countAll)
59+
->filter(fn (int $n) => 0 === $n % 2)
60+
->runningCount($countEven)
61+
->filter(fn (int $n) => $n % 3);
62+
63+
$this->assertSame(0, $countAll);
64+
$this->assertSame(1, $countEven);
65+
66+
foreach ($pipeline as $item) {
67+
$this->assertSame(2, $item);
68+
69+
break;
70+
}
71+
72+
// Because we need to inspect 3 numbers to get to 2: filtered out 0 and 1
73+
$this->assertSame(3, $countAll);
74+
$this->assertSame(3, $countEven);
75+
}
76+
77+
public function testRunningCountArray(): void
78+
{
79+
$countEven = 1;
80+
81+
$pipeline = take(range(0, 100))
82+
->runningCount($countAll)
83+
->filter(fn (int $n) => 0 === $n % 2)
84+
->runningCount($countEven)
85+
->filter(fn (int $n) => $n % 3);
86+
87+
$this->assertSame(101, $countAll);
88+
$this->assertSame(51, $countEven - 1);
89+
90+
$this->assertSame(34, $pipeline->count());
91+
}
92+
}

0 commit comments

Comments
 (0)