Skip to content

Commit d1f6deb

Browse files
authored
Add skipWhile() (#130)
Fixes #129
1 parent 27f5e07 commit d1f6deb

File tree

4 files changed

+105
-6
lines changed

4 files changed

+105
-6
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ All entry points always return an instance of the pipeline.
118118
| `unpack()` | Unpacks arrays into arguments for a callback. Flattens inputs if no callback provided. | |
119119
| `chunk()` | Chunks the pipeline into arrays of specified length. | `array_chunk` |
120120
| `filter()` | Removes elements unless a callback returns true. Removes falsey values if no callback provided. | `array_filter`, `Where` |
121+
| `skipWhile()` | Skips elements while the predicate returns true, and keeps everything after the predicate return false just once. | |
121122
| `slice()` | Extracts a slice from the inputs. Keys are not discarded intentionally. Suppors negative values for both arguments. | `array_slice` |
122123
| `fold()` | Reduces input values to a single value. Defaults to summation. Requires an initial value. | `array_reduce`, `Aggregate`, `Sum` |
123124
| `reduce()` | Alias to `fold()` with a reversed order of arguments. | `array_reduce` |

src/Standard.php

+29
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,35 @@ private static function resolvePredicate(?callable $func): callable
446446
return $func;
447447
}
448448

449+
/**
450+
* Skips elements while the predicate returns true, and keeps everything after the predicate return false just once.
451+
*
452+
* @param callable $predicate a callback returning boolean value
453+
*/
454+
public function skipWhile(callable $predicate): self
455+
{
456+
// No-op: an empty array or null.
457+
if ($this->empty()) {
458+
return $this;
459+
}
460+
461+
$predicate = self::resolvePredicate($predicate);
462+
463+
$this->filter(static function ($value) use ($predicate): bool {
464+
static $done = false;
465+
466+
if ($predicate($value) && !$done) {
467+
return false;
468+
}
469+
470+
$done = true;
471+
472+
return true;
473+
});
474+
475+
return $this;
476+
}
477+
449478
/**
450479
* Reduces input values to a single value. Defaults to summation. This is a terminal operation.
451480
*

tests/Helper/RunningVarianceTest.php

+2-6
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,7 @@ public function testMullerTransform(int $count, float $mean, float $sigma): void
242242
$numbers
243243
), $sigma / 10);
244244
} catch (Throwable $e) {
245-
if ($mean > 1E10) {
246-
$this->markTestSkipped($e->getMessage());
247-
}
248-
249-
throw $e;
245+
$this->assertGreaterThan(1E10, $mean, "Naive standard deviation calculation failed where it should not: {$e->getMessage()}");
250246
}
251247
}
252248

@@ -261,7 +257,7 @@ public function testMullerTransform(int $count, float $mean, float $sigma): void
261257
private static function getRandomNumbers(float $mean, float $sigma): iterable
262258
{
263259
$two_pi = 2 * M_PI;
264-
$epsilon = 1E-6; // Arbitrary number
260+
$epsilon = PHP_FLOAT_EPSILON;
265261

266262
while (true) {
267263
do {

tests/SkipWhileTest.php

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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 Pipeline\Standard;
24+
use function Pipeline\map;
25+
use function Pipeline\take;
26+
27+
/**
28+
* @covers \Pipeline\Standard
29+
*
30+
* @internal
31+
*/
32+
final class SkipWhileTest extends TestCase
33+
{
34+
public function testSkipEmpty(): void
35+
{
36+
$pipeline = new Standard();
37+
38+
$result = $pipeline
39+
->skipWhile(fn ($number) => 1 === $number)
40+
->toArray();
41+
42+
$this->assertSame([], $result);
43+
}
44+
45+
public function testSkipNever(): void
46+
{
47+
$result = take([2])
48+
->skipWhile(fn ($number) => 1 === $number)
49+
->toArray();
50+
51+
$this->assertSame([2], $result);
52+
}
53+
54+
public function testSkipWhileOnce(): void
55+
{
56+
$result = take([1, 1, 1, 2, 3, 4, 1, 2, 3])
57+
->skipWhile(fn ($number) => 1 === $number)
58+
->toArray();
59+
60+
$this->assertSame([2, 3, 4, 1, 2, 3], $result);
61+
}
62+
63+
public function testSkipWhileTwice()
64+
{
65+
$result = map(fn () => yield from [1, 1, 1, 2, 2, 3, 4, 5, 1, 2])
66+
->skipWhile(fn ($number) => 1 === $number)
67+
->skipWhile(fn ($number) => 2 === $number)
68+
->filter(fn ($number) => 1 === $number % 2)
69+
->toArray();
70+
71+
$this->assertSame([3, 5, 1], $result);
72+
}
73+
}

0 commit comments

Comments
 (0)