@@ -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