Skip to content

Commit

Permalink
Update Window operation.
Browse files Browse the repository at this point in the history
  • Loading branch information
drupol committed Sep 8, 2020
1 parent 8ae26f6 commit c78813b
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 115 deletions.
8 changes: 4 additions & 4 deletions docs/pages/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1551,15 +1551,15 @@ Loop the collection by yielding a specific window of data of a given length.

Interface: `Windowable`_

Signature: ``Collection::window(int ...$length);``
Signature: ``Collection::window(int $size);``

.. code-block:: php
$data = range('a', 'z');
$collection = Collection::with($data)
->window(2, 3)
->all();
Collection::fromIterable($data)
->window(2)
->all(); // [ ['a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ... ]
wrap
~~~~
Expand Down
7 changes: 1 addition & 6 deletions docs/pages/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,7 @@ Simple
// Traverse the collection using windows of a given size.
Collection::with(range('a', 'z'))
->window(3)
->all(); // [['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'e'], ...]
// Traverse the collection using windows of a given size.
Collection::with(range('a', 'z'))
->window(4, 2)
->all(); // [['a', 'b', 'c', 'd'], ['b', 'c'], ['c', 'd', 'e', 'f'], ['d', 'e'], ...]
->all(); // [['a'], ['a', 'b'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'e'], ...]
Collection::with(range('a', 'd'))
->wrap()
Expand Down
158 changes: 82 additions & 76 deletions spec/loophp/collection/CollectionSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,9 @@ public function it_can_cache(): void
$this::fromResource($fhandle)
->window(2)
->shouldIterateAs([
[],
[0 => 'a'],
[0 => 'a', 1 => 'b'],
[0 => 'a', 1 => 'b', 2 => 'c'],
]);

$fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb');
Expand All @@ -261,9 +263,9 @@ public function it_can_cache(): void
->cache()
->window(2)
->shouldIterateAs([
[0 => 'a'],
[0 => 'a', 1 => 'b'],
[1 => 'b', 2 => 'c'],
[2 => 'c'],
[0 => 'a', 1 => 'b', 2 => 'c'],
]);

$fhandle = fopen(__DIR__ . '/../../fixtures/sample.txt', 'rb');
Expand Down Expand Up @@ -2162,134 +2164,134 @@ public function it_can_use_with(): void
public function it_can_window(): void
{
$this::fromIterable(range('a', 'z'))
->window(2, 4, 3)
->window(2)
->shouldIterateAs([
0 => [
0 => 'a',
1 => 'b',
],
1 => [
0 => 'a',
1 => 'b',
2 => 'c',
3 => 'd',
4 => 'e',
],
2 => [
0 => 'a',
1 => 'b',
2 => 'c',
3 => 'd',
4 => 'e',
],
3 => [
3 => 'd',
4 => 'e',
0 => 'b',
1 => 'c',
2 => 'd',
],
4 => [
4 => 'e',
5 => 'f',
6 => 'g',
7 => 'h',
0 => 'c',
1 => 'd',
2 => 'e',
],
5 => [
5 => 'f',
6 => 'g',
7 => 'h',
0 => 'd',
1 => 'e',
2 => 'f',
],
6 => [
6 => 'g',
7 => 'h',
0 => 'e',
1 => 'f',
2 => 'g',
],
7 => [
7 => 'h',
8 => 'i',
9 => 'j',
10 => 'k',
0 => 'f',
1 => 'g',
2 => 'h',
],
8 => [
8 => 'i',
9 => 'j',
10 => 'k',
0 => 'g',
1 => 'h',
2 => 'i',
],
9 => [
9 => 'j',
10 => 'k',
0 => 'h',
1 => 'i',
2 => 'j',
],
10 => [
10 => 'k',
11 => 'l',
12 => 'm',
13 => 'n',
0 => 'i',
1 => 'j',
2 => 'k',
],
11 => [
11 => 'l',
12 => 'm',
13 => 'n',
0 => 'j',
1 => 'k',
2 => 'l',
],
12 => [
12 => 'm',
13 => 'n',
0 => 'k',
1 => 'l',
2 => 'm',
],
13 => [
13 => 'n',
14 => 'o',
15 => 'p',
16 => 'q',
0 => 'l',
1 => 'm',
2 => 'n',
],
14 => [
14 => 'o',
15 => 'p',
16 => 'q',
0 => 'm',
1 => 'n',
2 => 'o',
],
15 => [
15 => 'p',
16 => 'q',
0 => 'n',
1 => 'o',
2 => 'p',
],
16 => [
16 => 'q',
17 => 'r',
18 => 's',
19 => 't',
0 => 'o',
1 => 'p',
2 => 'q',
],
17 => [
17 => 'r',
18 => 's',
19 => 't',
0 => 'p',
1 => 'q',
2 => 'r',
],
18 => [
18 => 's',
19 => 't',
0 => 'q',
1 => 'r',
2 => 's',
],
19 => [
19 => 't',
20 => 'u',
21 => 'v',
22 => 'w',
0 => 'r',
1 => 's',
2 => 't',
],
20 => [
20 => 'u',
21 => 'v',
22 => 'w',
0 => 's',
1 => 't',
2 => 'u',
],
21 => [
21 => 'v',
22 => 'w',
0 => 't',
1 => 'u',
2 => 'v',
],
22 => [
22 => 'w',
23 => 'x',
24 => 'y',
25 => 'z',
0 => 'u',
1 => 'v',
2 => 'w',
],
23 => [
23 => 'x',
24 => 'y',
25 => 'z',
0 => 'v',
1 => 'w',
2 => 'x',
],
24 => [
24 => 'y',
25 => 'z',
0 => 'w',
1 => 'x',
2 => 'y',
],
25 => [
25 => 'z',
0 => 'x',
1 => 'y',
2 => 'z',
],
]);
}
Expand All @@ -2303,6 +2305,10 @@ public function it_can_wrap()
['b' => 'B'],
['c' => 'C'],
]);

$this::fromIterable(range('a', 'e'))
->window(0)
->shouldIterateAs(['a', 'b', 'c', 'd', 'e']);
}

public function it_can_zip(): void
Expand Down
4 changes: 2 additions & 2 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -737,9 +737,9 @@ public function unzip(): CollectionInterface
return $this->run(Unzip::of());
}

public function window(int ...$length): CollectionInterface
public function window(int $size): CollectionInterface
{
return $this->run(Window::of()(...$length));
return $this->run(Window::of()($size));
}

public static function with($data = [], ...$parameters): Collection
Expand Down
4 changes: 1 addition & 3 deletions src/Contract/Operation/Windowable.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
interface Windowable
{
/**
* @param int ...$length
*
* @psalm-return \loophp\collection\Contract\Collection<TKey, T>
*/
public function window(int ...$length): Collection;
public function window(int $size): Collection;
}
57 changes: 33 additions & 24 deletions src/Operation/Window.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

namespace loophp\collection\Operation;

use ArrayIterator;
use Closure;
use Generator;
use Iterator;

use function array_slice;

/**
* @psalm-template TKey
* @psalm-template TKey of array-key
Expand All @@ -17,31 +18,39 @@
final class Window extends AbstractOperation
{
/**
* @psalm-return Closure(int...): Closure(Iterator<TKey, T>): Generator<int, list<T>>
* @psalm-return Closure(int): Closure(Iterator<TKey, T>): Generator<TKey, list<T>>
*/
public function __invoke(): Closure
{
return static function (int ...$lengths): Closure {
return
/**
* @psalm-param Iterator<TKey, T> $iterator
* @psalm-param ArrayIterator<int, int> $length
*
* @psalm-return Generator<int, list<T>>
*/
static function (Iterator $iterator) use ($lengths): Generator {
/** @psalm-var Iterator<int, int> $lengths */
$lengths = Cycle::of()(new ArrayIterator($lengths));

for ($i = 0; iterator_count($iterator) > $i; ++$i) {
/** @psalm-var Generator<TKey, T> $slice */
$slice = Slice::of()($i)($lengths->current())($iterator);

yield iterator_to_array($slice);

$lengths->next();
}
};
};
return
/**
* @psalm-return Closure(Iterator<TKey, T>): Generator<TKey, list<T>>
*/
static function (int $size): Closure {
return
/**
* @psalm-param Iterator<TKey, T> $iterator
*
* @psalm-return Generator<TKey, list<T>>
*/
static function (Iterator $iterator) use ($size): Generator {
if (0 === $size) {
return yield from $iterator;
}

++$size;
$size *= -1;

/** @psalm-var list<T> $stack */
$stack = [];

for (; $iterator->valid(); $iterator->next()) {
// @todo Should we use Pack ?
$stack[$iterator->key()] = $iterator->current();

yield $iterator->key() => array_slice($stack, $size);
}
};
};
}
}

0 comments on commit c78813b

Please sign in to comment.