Skip to content

Commit

Permalink
[7.x] Add skipUntil and skipWhile methods to the collections (#32672
Browse files Browse the repository at this point in the history
)

* Add `skipUntil` and `skipWhile` methods to the collections

* Use the new `negate` method in `takeWhile`

* Add typehint
  • Loading branch information
JosephSilber authored May 4, 2020
1 parent 1eeee00 commit a00484a
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 4 deletions.
22 changes: 22 additions & 0 deletions src/Illuminate/Support/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,28 @@ public function skip($count)
return $this->slice($count);
}

/**
* Skip items in the collection until the given condition is met.
*
* @param mixed $value
* @return static
*/
public function skipUntil($value)
{
return new static($this->lazy()->skipUntil($value)->all());
}

/**
* Skip items in the collection while the given condition is met.
*
* @param mixed $value
* @return static
*/
public function skipWhile($value)
{
return new static($this->lazy()->skipWhile($value)->all());
}

/**
* Slice the underlying collection array.
*
Expand Down
42 changes: 39 additions & 3 deletions src/Illuminate/Support/LazyCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,44 @@ public function skip($count)
});
}

/**
* Skip items in the collection until the given condition is met.
*
* @param mixed $value
* @return static
*/
public function skipUntil($value)
{
$callback = $this->useAsCallable($value) ? $value : $this->equality($value);

return $this->skipWhile($this->negate($callback));
}

/**
* Skip items in the collection while the given condition is met.
*
* @param mixed $value
* @return static
*/
public function skipWhile($value)
{
$callback = $this->useAsCallable($value) ? $value : $this->equality($value);

return new static(function () use ($callback) {
$iterator = $this->getIterator();

while ($iterator->valid() && $callback($iterator->current(), $iterator->key())) {
$iterator->next();
}

while ($iterator->valid()) {
yield $iterator->key() => $iterator->current();

$iterator->next();
}
});
}

/**
* Get a slice of items from the enumerable.
*
Expand Down Expand Up @@ -1145,9 +1183,7 @@ public function takeWhile($value)
{
$callback = $this->useAsCallable($value) ? $value : $this->equality($value);

return $this->takeUntil(function ($item, $key) use ($callback) {
return ! $callback($item, $key);
});
return $this->takeUntil($this->negate($callback));
}

/**
Expand Down
16 changes: 15 additions & 1 deletion src/Illuminate/Support/Traits/EnumeratesValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Illuminate\Support\Traits;

use CachingIterator;
use Closure;
use Exception;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
Expand Down Expand Up @@ -965,7 +966,7 @@ protected function valueRetriever($value)
/**
* Make a function to check an item's equality.
*
* @param \Closure|mixed $value
* @param mixed $value
* @return \Closure
*/
protected function equality($value)
Expand All @@ -974,4 +975,17 @@ protected function equality($value)
return $item === $value;
};
}

/**
* Make a function using another function, by negating its result.
*
* @param \Closure $callback
* @return \Closure
*/
protected function negate(Closure $callback)
{
return function (...$params) use ($callback) {
return ! $callback(...$params);
};
}
}
36 changes: 36 additions & 0 deletions tests/Support/SupportCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,42 @@ public function testSkipMethod($collection)
$this->assertSame([5, 6], $data->all());
}

/**
* @dataProvider collectionClassProvider
*/
public function testSkipUntil($collection)
{
$data = new $collection([1, 1, 2, 2, 3, 3, 4, 4]);

$data = $data->skipUntil(3)->values();

$this->assertSame([3, 3, 4, 4], $data->all());

$data = $data->skipUntil(function ($value, $key) {
return $value > 3;
})->values();

$this->assertSame([4, 4], $data->all());
}

/**
* @dataProvider collectionClassProvider
*/
public function testSkipWhile($collection)
{
$data = new $collection([1, 1, 2, 2, 3, 3, 4, 4]);

$data = $data->skipWhile(1)->values();

$this->assertSame([2, 2, 3, 3, 4, 4], $data->all());

$data = $data->skipWhile(function ($value, $key) {
return $value < 3;
})->values();

$this->assertSame([3, 3, 4, 4], $data->all());
}

/**
* @dataProvider collectionClassProvider
*/
Expand Down
34 changes: 34 additions & 0 deletions tests/Support/SupportLazyCollectionIsLazyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,40 @@ public function testSkipIsLazy()
});
}

public function testSkipUntilIsLazy()
{
$this->assertDoesNotEnumerate(function ($collection) {
$collection->skipUntil(INF);
});

$this->assertEnumerates(10, function ($collection) {
$collection->skipUntil(10)->first();
});

$this->assertEnumerates(10, function ($collection) {
$collection->skipUntil(function ($item) {
return $item === 10;
})->first();
});
}

public function testSkipWhileIsLazy()
{
$this->assertDoesNotEnumerate(function ($collection) {
$collection->skipWhile(1);
});

$this->assertEnumerates(2, function ($collection) {
$collection->skipWhile(1)->first();
});

$this->assertEnumerates(10, function ($collection) {
$collection->skipWhile(function ($item) {
return $item < 10;
})->first();
});
}

public function testSliceIsLazy()
{
$this->assertDoesNotEnumerate(function ($collection) {
Expand Down

0 comments on commit a00484a

Please sign in to comment.