Skip to content

Commit

Permalink
Add skipWhile() (#130)
Browse files Browse the repository at this point in the history
Fixes #129
  • Loading branch information
sanmai authored Jun 13, 2023
1 parent 27f5e07 commit d1f6deb
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 6 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ All entry points always return an instance of the pipeline.
| `unpack()` | Unpacks arrays into arguments for a callback. Flattens inputs if no callback provided. | |
| `chunk()` | Chunks the pipeline into arrays of specified length. | `array_chunk` |
| `filter()` | Removes elements unless a callback returns true. Removes falsey values if no callback provided. | `array_filter`, `Where` |
| `skipWhile()` | Skips elements while the predicate returns true, and keeps everything after the predicate return false just once. | |
| `slice()` | Extracts a slice from the inputs. Keys are not discarded intentionally. Suppors negative values for both arguments. | `array_slice` |
| `fold()` | Reduces input values to a single value. Defaults to summation. Requires an initial value. | `array_reduce`, `Aggregate`, `Sum` |
| `reduce()` | Alias to `fold()` with a reversed order of arguments. | `array_reduce` |
Expand Down
29 changes: 29 additions & 0 deletions src/Standard.php
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,35 @@ private static function resolvePredicate(?callable $func): callable
return $func;
}

/**
* Skips elements while the predicate returns true, and keeps everything after the predicate return false just once.
*
* @param callable $predicate a callback returning boolean value
*/
public function skipWhile(callable $predicate): self
{
// No-op: an empty array or null.
if ($this->empty()) {
return $this;
}

$predicate = self::resolvePredicate($predicate);

$this->filter(static function ($value) use ($predicate): bool {
static $done = false;

if ($predicate($value) && !$done) {
return false;
}

$done = true;

return true;
});

return $this;
}

/**
* Reduces input values to a single value. Defaults to summation. This is a terminal operation.
*
Expand Down
8 changes: 2 additions & 6 deletions tests/Helper/RunningVarianceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,7 @@ public function testMullerTransform(int $count, float $mean, float $sigma): void
$numbers
), $sigma / 10);
} catch (Throwable $e) {
if ($mean > 1E10) {
$this->markTestSkipped($e->getMessage());
}

throw $e;
$this->assertGreaterThan(1E10, $mean, "Naive standard deviation calculation failed where it should not: {$e->getMessage()}");
}
}

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

while (true) {
do {
Expand Down
73 changes: 73 additions & 0 deletions tests/SkipWhileTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
/**
* Copyright 2017, 2018 Alexey Kopytko <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

declare(strict_types=1);

namespace Tests\Pipeline;

use PHPUnit\Framework\TestCase;
use Pipeline\Standard;
use function Pipeline\map;
use function Pipeline\take;

/**
* @covers \Pipeline\Standard
*
* @internal
*/
final class SkipWhileTest extends TestCase
{
public function testSkipEmpty(): void
{
$pipeline = new Standard();

$result = $pipeline
->skipWhile(fn ($number) => 1 === $number)
->toArray();

$this->assertSame([], $result);
}

public function testSkipNever(): void
{
$result = take([2])
->skipWhile(fn ($number) => 1 === $number)
->toArray();

$this->assertSame([2], $result);
}

public function testSkipWhileOnce(): void
{
$result = take([1, 1, 1, 2, 3, 4, 1, 2, 3])
->skipWhile(fn ($number) => 1 === $number)
->toArray();

$this->assertSame([2, 3, 4, 1, 2, 3], $result);
}

public function testSkipWhileTwice()
{
$result = map(fn () => yield from [1, 1, 1, 2, 2, 3, 4, 5, 1, 2])
->skipWhile(fn ($number) => 1 === $number)
->skipWhile(fn ($number) => 2 === $number)
->filter(fn ($number) => 1 === $number % 2)
->toArray();

$this->assertSame([3, 5, 1], $result);
}
}

0 comments on commit d1f6deb

Please sign in to comment.