Skip to content

Commit 3ce83f6

Browse files
committed
Add Iterator#chunk to allow splitting iterator values into Arrays
1 parent 8e755c3 commit 3ce83f6

File tree

4 files changed

+80
-0
lines changed

4 files changed

+80
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ and this project adheres to
1414
- `common.mkdirpPromise()` function.
1515
- `Iterator#apply()` and `Iterator#chainApply()` to improve iterator
1616
interaction with chained calls.
17+
- `Iterator#chunks()` to allow splitting iterator via custom condition into
18+
Arrays of values.
1719

1820
### Changed
1921

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,16 @@ _Result:_
847847
'3, -1';
848848
```
849849

850+
#### Iterator.prototype.chunk(from)
851+
852+
- `from`: [`<Function>`][function]|[`<number>`][number] split function or chunk
853+
size
854+
- `val`: `<any>` current iterator value
855+
856+
Split iterator into chunks of size `from` or every time function
857+
858+
`from` returns falsy value.
859+
850860
#### Iterator.prototype.collectTo(CollectionClass)
851861

852862
#### Iterator.prototype.collectWith(obj, collector)

lib/iterator.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,19 @@ class Iterator {
222222
return iter(res && res[Symbol.iterator] ? res : [res]);
223223
}
224224

225+
// Split iterator into chunks of size `from` or every time function
226+
// `from` returns falsy value.
227+
// from - <Function> | <number> split function or chunk size
228+
// val <any> current iterator value
229+
chunk(from) {
230+
if (typeof from === 'number') {
231+
const num = from;
232+
let counter = 0;
233+
from = () => counter++ % num === 0;
234+
}
235+
return new ChunkIterator(this, from);
236+
}
237+
225238
// Create iterator iterating over the range
226239
// Signature: start, stop[, step]
227240
// start <number>
@@ -490,6 +503,26 @@ class SkipWhileIterator extends Iterator {
490503
}
491504
}
492505

506+
class ChunkIterator extends Iterator {
507+
constructor(base, fn) {
508+
super(base);
509+
this.fn = fn;
510+
this.value = [];
511+
}
512+
513+
next() {
514+
let next = this.base.next();
515+
if (next.done) return next;
516+
while (!next.done && (!this.fn(next.value) || this.value.length === 0)) {
517+
this.value.push(next.value);
518+
next = this.base.next();
519+
}
520+
const value = this.value;
521+
this.value = [next.value];
522+
return { done: false, value };
523+
}
524+
}
525+
493526
const iter = base => new Iterator(base);
494527

495528
module.exports = {

test/iterator.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,41 @@ metatests.testSync('Iterator.chainApply on string', test => {
643643
test.strictSame(actual, 'h e l l o');
644644
});
645645

646+
metatests.testSync('Iterator.chunk', test => {
647+
const actual = iter([1, 2, 3, 1, 4, 5, 1, 6, 7])
648+
.chunk(v => v === 1)
649+
.toArray();
650+
test.strictSame(actual, [[1, 2, 3], [1, 4, 5], [1, 6, 7]]);
651+
});
652+
653+
metatests.testSync('Iterator.chunk with number', test => {
654+
const actual = iter([1, 2, 3, 1, 4, 5, 1, 6, 7])
655+
.chunk(3)
656+
.toArray();
657+
test.strictSame(actual, [[1, 2, 3], [1, 4, 5], [1, 6, 7]]);
658+
});
659+
660+
metatests.testSync('Iterator.chunk with empty iterator', test => {
661+
const actual = iter([])
662+
.chunk(3)
663+
.toArray();
664+
test.strictSame(actual, []);
665+
});
666+
667+
metatests.testSync('Iterator.chunk with single chunk', test => {
668+
const actual = iter([1, 2, 3, 1, 4, 5, 1, 6, 7])
669+
.chunk(() => false)
670+
.toArray();
671+
test.strictSame(actual, [[1, 2, 3, 1, 4, 5, 1, 6, 7]]);
672+
});
673+
674+
metatests.testSync('Iterator.chunk with empty chunks', test => {
675+
const actual = iter([1, 1, 3, 3, 3, 5, 5])
676+
.chunk(x => x === 3)
677+
.toArray();
678+
test.strictSame(actual, [[1, 1], [3], [3], [3, 5, 5]]);
679+
});
680+
646681
metatests.testSync('iterEntries must iterate over object entries', test => {
647682
const source = { a: 13, b: 42, c: 'hello' };
648683
test.strictSame(iterEntries(source).toArray(), Object.entries(source));

0 commit comments

Comments
 (0)