Skip to content

Commit

Permalink
feat: Add Span operation.
Browse files Browse the repository at this point in the history
  • Loading branch information
drupol committed Oct 4, 2020
1 parent 39ad38f commit 48d9620
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 0 deletions.
17 changes: 17 additions & 0 deletions docs/pages/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,22 @@ Signature: ``Collection::sort(?callable $callback = null);``
->sort() // Sort the values (which are now the keys)
->flip(); // Flip again to put back the keys and values, sorted by keys.
span
~~~~

Returns a tuple where first element is longest prefix (possibly empty) of elements that satisfy the callback and second element is the remainder.

Interface: `Spanable`_

Signature: ``Collection::span(callable $callback);``

.. code-block:: php
$input = range(1, 10);
Collection::fromIterable($input)
->span(fn ($x) => $x < 4); // [ [1, 2, 3], [4, 5, 6, 7, 8, 9, 10] ]
split
~~~~~

Expand Down Expand Up @@ -1974,6 +1990,7 @@ Signature: ``Collection::zip(iterable ...$iterables);``
.. _Sinceable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sinceable.php
.. _Sliceable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sliceable.php
.. _Sortable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sortable.php
.. _Spanable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Spanable.php
.. _Splitable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Splitable.php
.. _Tailable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Tailable.php
.. _Tailsable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Tailsable.php
Expand Down
22 changes: 22 additions & 0 deletions spec/loophp/collection/CollectionSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -1986,6 +1986,28 @@ static function ($left, $right): int {
->shouldIterateAs($output());
}

public function it_can_span(): void
{
$input = range(1, 10);

$test = $this::fromIterable($input)
->span(static function (int $x): bool {return 4 > $x; });

$test
->first()
->current()
->shouldIterateAs(
[1, 2, 3]
);

$test
->last()
->current()
->shouldIterateAs(
[3 => 4, 4 => 5, 5 => 6, 6 => 7, 7 => 8, 8 => 9, 9 => 10]
);
}

public function it_can_split(): void
{
$splitter = static function ($value): bool {
Expand Down
6 changes: 6 additions & 0 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
use loophp\collection\Operation\Since;
use loophp\collection\Operation\Slice;
use loophp\collection\Operation\Sort;
use loophp\collection\Operation\Span;
use loophp\collection\Operation\Split;
use loophp\collection\Operation\Tail;
use loophp\collection\Operation\Tails;
Expand Down Expand Up @@ -746,6 +747,11 @@ public function sort(int $type = Operation\Sortable::BY_VALUES, ?callable $callb
return $this->run(Sort::of()($type)($callback));
}

public function span(callable $callback): CollectionInterface
{
return $this->run(Span::of()($callback));
}

public function split(int $type = Operation\Splitable::BEFORE, callable ...$callbacks): CollectionInterface
{
return $this->run(Split::of()($type)(...$callbacks));
Expand Down
3 changes: 3 additions & 0 deletions src/Contract/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
use loophp\collection\Contract\Operation\Sinceable;
use loophp\collection\Contract\Operation\Sliceable;
use loophp\collection\Contract\Operation\Sortable;
use loophp\collection\Contract\Operation\Spanable;
use loophp\collection\Contract\Operation\Splitable;
use loophp\collection\Contract\Operation\Tailable;
use loophp\collection\Contract\Operation\Tailsable;
Expand Down Expand Up @@ -178,6 +179,7 @@
* @template-extends Sinceable<TKey, T>
* @template-extends Sliceable<TKey, T>
* @template-extends Sortable<TKey, T>
* @template-extends Spanable<TKey, T>
* @template-extends Splitable<TKey, T>
* @template-extends Tailable<TKey, T>
* @template-extends Tailsable<TKey, T>
Expand Down Expand Up @@ -275,6 +277,7 @@ interface Collection extends
Sinceable,
Sliceable,
Sortable,
Spanable,
Splitable,
Tailable,
Tailsable,
Expand Down
20 changes: 20 additions & 0 deletions src/Contract/Operation/Spanable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace loophp\collection\Contract\Operation;

use loophp\collection\Contract\Collection;

/**
* @psalm-template TKey
* @psalm-template TKey of array-key
* @psalm-template T
*/
interface Spanable
{
/**
* @psalm-return \loophp\collection\Contract\Collection<TKey, T>
*/
public function span(callable $callback): Collection;
}
48 changes: 48 additions & 0 deletions src/Operation/Span.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace loophp\collection\Operation;

use Closure;
use Generator;
use Iterator;

/**
* @psalm-template TKey
* @psalm-template TKey of array-key
* @psalm-template T
*
* phpcs:disable Generic.Files.LineLength.TooLong
*/
final class Span extends AbstractOperation
{
/**
* @psalm-return Closure((callable(T, TKey, Iterator<TKey, T>): bool)): Closure(Iterator<TKey, T>): Generator<int, Iterator<TKey, T>>
*/
public function __invoke(): Closure
{
return
/**
* @psalm-param callable(T, TKey, Iterator<TKey, T>):bool $callback
*
* @psalm-return Closure(Iterator<TKey, T>): Generator<int, Iterator<TKey, T>>
*/
static function (callable $callback): Closure {
return
/**
* @psalm-param Iterator<TKey, T> $iterator
*
* @psalm-return Generator<int, Iterator<TKey, T>>
*/
static function (Iterator $iterator) use ($callback): Generator {
/** @psalm-var Iterator<TKey, T> $takeWhile */
$takeWhile = TakeWhile::of()($callback)($iterator);
/** @psalm-var Iterator<TKey, T> $dropWhile */
$dropWhile = DropWhile::of()($callback)($iterator);

return yield from [$takeWhile, $dropWhile];
};
};
}
}

0 comments on commit 48d9620

Please sign in to comment.