Skip to content

Commit af81fd3

Browse files
committed
Implement chunked() and windowed()
Inspired by https://kotlinlang.org/docs/collection-parts.html See also #14 and #56
1 parent c6ac43c commit af81fd3

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed

src/main/php/util/data/Sequence.class.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,76 @@ public function sorted($comparator= null) {
642642
return new self($sort);
643643
}
644644

645+
/**
646+
* Returns a chunked stream with chunks not exceeding the given size.
647+
* The last chunk may have a smaller size.
648+
*
649+
* @param int $size
650+
* @return self
651+
* @throws lang.IllegalArgumentException
652+
*/
653+
public function chunked($size) {
654+
if ($size <= 0) {
655+
throw new IllegalArgumentException('Size must be greater than zero');
656+
}
657+
658+
$f= function() use($size) {
659+
$chunk= [];
660+
foreach ($this->elements as $element) {
661+
$chunk[]= $element;
662+
if (sizeof($chunk) < $size) continue;
663+
664+
yield $chunk;
665+
$chunk= [];
666+
}
667+
if ($chunk) yield $chunk;
668+
};
669+
return new self($f());
670+
}
671+
672+
/**
673+
* Returns a sliding window stream - a list of element ranges that you
674+
* would see if you were looking at the collection through a sliding
675+
* window of the given size.
676+
*
677+
* @param int $size
678+
* @param int $step
679+
* @param bool $partial
680+
* @return self
681+
* @throws lang.IllegalArgumentException
682+
*/
683+
public function windowed($size, $step= 1, $partial= false) {
684+
if ($size <= 0 || $step <= 0) {
685+
throw new IllegalArgumentException('Both size and step must be greater than zero');
686+
}
687+
688+
$f= function() use($size, $step, $partial) {
689+
$it= $this->getIterator();
690+
$chunk= [];
691+
do {
692+
693+
// Fetch $size elements and yield them as a chunk
694+
while (sizeof($chunk) < $size && $it->valid()) {
695+
$chunk[]= $it->current();
696+
$it->next();
697+
}
698+
if ($chunk && $partial || $size === sizeof($chunk)) yield $chunk;
699+
700+
// Step forward, potentially skipping some elements
701+
$s= $step - sizeof($chunk);
702+
if ($s > 0) {
703+
while ($s-- > 0 && $it->valid()) $it->next();
704+
$chunk= [];
705+
} else {
706+
$chunk= array_slice($chunk, $step);
707+
}
708+
} while ($it->valid());
709+
710+
if ($chunk && $partial) yield $chunk;
711+
};
712+
return new self($f());
713+
}
714+
645715
/** @return string */
646716
public function hashCode() {
647717
return 'S'.Objects::hashOf($this->elements);

0 commit comments

Comments
 (0)