Skip to content

Commit a00484a

Browse files
authored
[7.x] Add skipUntil and skipWhile methods to the collections (#32672)
* Add `skipUntil` and `skipWhile` methods to the collections * Use the new `negate` method in `takeWhile` * Add typehint
1 parent 1eeee00 commit a00484a

File tree

5 files changed

+146
-4
lines changed

5 files changed

+146
-4
lines changed

src/Illuminate/Support/Collection.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,28 @@ public function skip($count)
978978
return $this->slice($count);
979979
}
980980

981+
/**
982+
* Skip items in the collection until the given condition is met.
983+
*
984+
* @param mixed $value
985+
* @return static
986+
*/
987+
public function skipUntil($value)
988+
{
989+
return new static($this->lazy()->skipUntil($value)->all());
990+
}
991+
992+
/**
993+
* Skip items in the collection while the given condition is met.
994+
*
995+
* @param mixed $value
996+
* @return static
997+
*/
998+
public function skipWhile($value)
999+
{
1000+
return new static($this->lazy()->skipWhile($value)->all());
1001+
}
1002+
9811003
/**
9821004
* Slice the underlying collection array.
9831005
*

src/Illuminate/Support/LazyCollection.php

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,44 @@ public function skip($count)
947947
});
948948
}
949949

950+
/**
951+
* Skip items in the collection until the given condition is met.
952+
*
953+
* @param mixed $value
954+
* @return static
955+
*/
956+
public function skipUntil($value)
957+
{
958+
$callback = $this->useAsCallable($value) ? $value : $this->equality($value);
959+
960+
return $this->skipWhile($this->negate($callback));
961+
}
962+
963+
/**
964+
* Skip items in the collection while the given condition is met.
965+
*
966+
* @param mixed $value
967+
* @return static
968+
*/
969+
public function skipWhile($value)
970+
{
971+
$callback = $this->useAsCallable($value) ? $value : $this->equality($value);
972+
973+
return new static(function () use ($callback) {
974+
$iterator = $this->getIterator();
975+
976+
while ($iterator->valid() && $callback($iterator->current(), $iterator->key())) {
977+
$iterator->next();
978+
}
979+
980+
while ($iterator->valid()) {
981+
yield $iterator->key() => $iterator->current();
982+
983+
$iterator->next();
984+
}
985+
});
986+
}
987+
950988
/**
951989
* Get a slice of items from the enumerable.
952990
*
@@ -1145,9 +1183,7 @@ public function takeWhile($value)
11451183
{
11461184
$callback = $this->useAsCallable($value) ? $value : $this->equality($value);
11471185

1148-
return $this->takeUntil(function ($item, $key) use ($callback) {
1149-
return ! $callback($item, $key);
1150-
});
1186+
return $this->takeUntil($this->negate($callback));
11511187
}
11521188

11531189
/**

src/Illuminate/Support/Traits/EnumeratesValues.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Illuminate\Support\Traits;
44

55
use CachingIterator;
6+
use Closure;
67
use Exception;
78
use Illuminate\Contracts\Support\Arrayable;
89
use Illuminate\Contracts\Support\Jsonable;
@@ -965,7 +966,7 @@ protected function valueRetriever($value)
965966
/**
966967
* Make a function to check an item's equality.
967968
*
968-
* @param \Closure|mixed $value
969+
* @param mixed $value
969970
* @return \Closure
970971
*/
971972
protected function equality($value)
@@ -974,4 +975,17 @@ protected function equality($value)
974975
return $item === $value;
975976
};
976977
}
978+
979+
/**
980+
* Make a function using another function, by negating its result.
981+
*
982+
* @param \Closure $callback
983+
* @return \Closure
984+
*/
985+
protected function negate(Closure $callback)
986+
{
987+
return function (...$params) use ($callback) {
988+
return ! $callback(...$params);
989+
};
990+
}
977991
}

tests/Support/SupportCollectionTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,42 @@ public function testSkipMethod($collection)
212212
$this->assertSame([5, 6], $data->all());
213213
}
214214

215+
/**
216+
* @dataProvider collectionClassProvider
217+
*/
218+
public function testSkipUntil($collection)
219+
{
220+
$data = new $collection([1, 1, 2, 2, 3, 3, 4, 4]);
221+
222+
$data = $data->skipUntil(3)->values();
223+
224+
$this->assertSame([3, 3, 4, 4], $data->all());
225+
226+
$data = $data->skipUntil(function ($value, $key) {
227+
return $value > 3;
228+
})->values();
229+
230+
$this->assertSame([4, 4], $data->all());
231+
}
232+
233+
/**
234+
* @dataProvider collectionClassProvider
235+
*/
236+
public function testSkipWhile($collection)
237+
{
238+
$data = new $collection([1, 1, 2, 2, 3, 3, 4, 4]);
239+
240+
$data = $data->skipWhile(1)->values();
241+
242+
$this->assertSame([2, 2, 3, 3, 4, 4], $data->all());
243+
244+
$data = $data->skipWhile(function ($value, $key) {
245+
return $value < 3;
246+
})->values();
247+
248+
$this->assertSame([3, 3, 4, 4], $data->all());
249+
}
250+
215251
/**
216252
* @dataProvider collectionClassProvider
217253
*/

tests/Support/SupportLazyCollectionIsLazyTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,40 @@ public function testSkipIsLazy()
850850
});
851851
}
852852

853+
public function testSkipUntilIsLazy()
854+
{
855+
$this->assertDoesNotEnumerate(function ($collection) {
856+
$collection->skipUntil(INF);
857+
});
858+
859+
$this->assertEnumerates(10, function ($collection) {
860+
$collection->skipUntil(10)->first();
861+
});
862+
863+
$this->assertEnumerates(10, function ($collection) {
864+
$collection->skipUntil(function ($item) {
865+
return $item === 10;
866+
})->first();
867+
});
868+
}
869+
870+
public function testSkipWhileIsLazy()
871+
{
872+
$this->assertDoesNotEnumerate(function ($collection) {
873+
$collection->skipWhile(1);
874+
});
875+
876+
$this->assertEnumerates(2, function ($collection) {
877+
$collection->skipWhile(1)->first();
878+
});
879+
880+
$this->assertEnumerates(10, function ($collection) {
881+
$collection->skipWhile(function ($item) {
882+
return $item < 10;
883+
})->first();
884+
});
885+
}
886+
853887
public function testSliceIsLazy()
854888
{
855889
$this->assertDoesNotEnumerate(function ($collection) {

0 commit comments

Comments
 (0)