Skip to content

Commit

Permalink
Add Iterator#chunk to allow splitting iterator values into Arrays
Browse files Browse the repository at this point in the history
  • Loading branch information
lundibundi committed Sep 17, 2019
1 parent 8e755c3 commit b77fa98
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ and this project adheres to
- `common.mkdirpPromise()` function.
- `Iterator#apply()` and `Iterator#chainApply()` to improve iterator
interaction with chained calls.
- `Iterator#chunks()` to allow splitting iterator via custom condition into
Arrays of values.

### Changed

Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,16 @@ _Result:_
'3, -1';
```

#### Iterator.prototype.chunk(from)

- `from`: [`<Function>`][function]|[`<number>`][number] split function or chunk
size
- `val`: `<any>` current iterator value

Split iterator into chunks of size `from` or every time function

`from` returns falsy value.

#### Iterator.prototype.collectTo(CollectionClass)

#### Iterator.prototype.collectWith(obj, collector)
Expand Down
33 changes: 33 additions & 0 deletions lib/iterator.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,19 @@ class Iterator {
return iter(res && res[Symbol.iterator] ? res : [res]);
}

// Split iterator into chunks of size `from` or every time function
// `from` returns falsy value.
// from - <Function> | <number> split function or chunk size
// val <any> current iterator value
chunk(from) {
if (typeof from === 'number') {
const num = from;
let counter = 0;
from = () => counter++ % num === 0;
}
return new ChunkIterator(this, from);
}

// Create iterator iterating over the range
// Signature: start, stop[, step]
// start <number>
Expand Down Expand Up @@ -490,6 +503,26 @@ class SkipWhileIterator extends Iterator {
}
}

class ChunkIterator extends Iterator {
constructor(base, fn) {
super(base);
this.fn = fn;
this.value = [];
}

next() {
let next = this.base.next();
if (next.done && this.value.length === 0) return next;
while (!next.done && (!this.fn(next.value) || this.value.length === 0)) {
this.value.push(next.value);
next = this.base.next();
}
const value = this.value;
this.value = next.done ? [] : [next.value];
return { done: false, value };
}
}

const iter = base => new Iterator(base);

module.exports = {
Expand Down
43 changes: 43 additions & 0 deletions test/iterator.js
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,49 @@ metatests.testSync('Iterator.chainApply on string', test => {
test.strictSame(actual, 'h e l l o');
});

metatests.testSync('Iterator.chunk', test => {
const actual = iter([1, 2, 3, 1, 4, 5, 1, 6, 7])
.chunk(v => v === 1)
.toArray();
test.strictSame(actual, [[1, 2, 3], [1, 4, 5], [1, 6, 7]]);
});

metatests.testSync('Iterator.chunk with number', test => {
const actual = iter([1, 2, 3, 1, 4, 5, 1, 6, 7])
.chunk(3)
.toArray();
test.strictSame(actual, [[1, 2, 3], [1, 4, 5], [1, 6, 7]]);
});

metatests.testSync('Iterator.chunk with empty iterator', test => {
const actual = iter([])
.chunk(3)
.toArray();
test.strictSame(actual, []);
});

metatests.testSync('Iterator.chunk with single chunk', test => {
const actual = iter([1, 2, 3, 1, 4, 5, 1, 6, 7])
.chunk(() => false)
.toArray();
test.strictSame(actual, [[1, 2, 3, 1, 4, 5, 1, 6, 7]]);
});

metatests.testSync('Iterator.chunk with empty chunks', test => {
const actual = iter([1, 1, 3, 3, 3, 5, 5])
.chunk(x => x === 3)
.toArray();
test.strictSame(actual, [[1, 1], [3], [3], [3, 5, 5]]);
});

metatests.testSync('Iterator.chunk with all chunks', test => {
const actual = iter([1, 1, 3, 3, 3, 5, 5])
.chunk(() => true)
.toArray();
test.log(actual);
test.strictSame(actual, [[1], [1], [3], [3], [3], [5], [5]]);
});

metatests.testSync('iterEntries must iterate over object entries', test => {
const source = { a: 13, b: 42, c: 'hello' };
test.strictSame(iterEntries(source).toArray(), Object.entries(source));
Expand Down

0 comments on commit b77fa98

Please sign in to comment.