Skip to content
Permalink
Browse files

feat: Provide chunkify functions

  • Loading branch information...
koraa committed Aug 27, 2019
1 parent 533cff4 commit 9ff9603c981e1e38cbc1623f93233356d6ee6ba5
Showing with 112 additions and 6 deletions.
  1. +94 −4 src/sequence.js
  2. +18 −2 test/sequence.test.js
@@ -915,7 +915,7 @@ const into = curry('into', (seq, t) => Into.invoke(t, seq));
* ```
* # Remove odd numbers from a set
* const st = new Set([1,1,2,2,3,4,5]);
* into(filter(st, n => n % 2 == 0), Set) # Set(2,4)
* into(filter(st, n => n % 2 === 0), Set) # Set(2,4)
*
* # Remove a key/value pair from an object
* const obj = {foo: 42, bar: 5};
@@ -1053,7 +1053,7 @@ const map = curry('map', function* map(seq, fn) {
* Remove values from the sequence based on the given condition.
*
* ```
* filter(range(0,10), x => x%2 == 0) // [2,4,6,8]
* filter(range(0,10), x => x%2 === 0) // [2,4,6,8]
* ```
*
* @function
@@ -1448,7 +1448,7 @@ const zipLongest2 = curry('zipLongest2', (a, b, fallback) => zipLongest([a, b],
* Will throw IteratorEnded if the sequence is shorter than
* the given window.
*
* Returns an empty sequence if `no == 0`.
* Returns an empty sequence if `no === 0`.
*
* @function
* @param {Sequence} seq A sequence of sequences
@@ -1483,7 +1483,7 @@ const slidingWindow = curry('slidingWindow', (seq, no) => {
* Like slidingWindow, but returns an empty sequence if the given
* sequence is too short.
*
* Returns an empty sequence if `no == 0`.
* Returns an empty sequence if `no === 0`.
*
* @function
* @param {Sequence} seq A sequence of sequences
@@ -1529,6 +1529,8 @@ const trySlidingWindow = curry('trySlidingWindow', function* trySlidingWindow(se
* Try sliding window would yield an empty array in each of the examples
* above.
*
* Returns an empty sequence if `no === 0`.
*
* @function
* @param {Sequence} seq
* @param {Number} no Number of elements to look ahead to.
@@ -1540,6 +1542,91 @@ const lookahead = curry('lookahead', (seq, no, filler) => {
return trySlidingWindow(filled, no + 1);
});

/**
* Split the given input sequence into chunks of a specific length.
* The last chunk may be shorter than the given chunk size if the input
* sequence is not long enough.
*
* ```
* const { list, chunkifyShort } = require('ferrum');
* list(chunkifyShort([1,2,3,4,5], 2)); // => [[1,2], [3,4], [5]]
* ```
*
* Returns an empty sequence if `no === 0`.
*
* @function
* @param {Sequence} seq A sequence of sequences
* @param {Number} len The length of the chunk
* @returns {Iterator} Sequence of lists
*/
const chunkifyShort = curry('chunkifyShort', (seq, len) => {
if (len === 0) {
return iter([]);
}

const it = iter(seq);
return pipe(
repeatFn(() => takeShort(it, len)),
takeWhile(chunk => !empty(chunk)),
);
});

/**
* Split the given input sequence into chunks of a specific length.
* If the length of the sequence is not divisible by the chunk length
* IteratorEnded will be thrown.
*
* ```
* const { list, chunkify } = require('ferrum');
* list(chunkify([1,2,3,4], 2)); // => [[1,2], [3,4]]
* ```
*
* Returns an empty sequence if `no === 0`.
*
* @function
* @param {Sequence} seq A sequence of sequences
* @param {Number} len The length of the chunk
* @throws {IteratorEnded}
* @returns {Iterator} Sequence of lists
*/
const chunkify = curry('chunkify', (seq, len) => pipe(
chunkifyShort(seq, len),
map((chunk) => {
if (size(chunk) === len) {
return chunk;
} else {
throw new IteratorEnded('chunkify() needs sequences of the correct length!');
}
}),
));

/**
* Split the given input sequence into chunks of a specific length.
* If the input sequence is not long enough, the last chunk will be filled
* with the given fallback value.
*
* ```
* const { list, chunkifyWithFallback } = require('ferrum');
* list(chunkifyWithFallback([1,2,3,4,5], 2), 99); // => [[1,2], [3,4], [5, 99]]
* ```
*
* @function
* @param {Sequence} seq A sequence of sequences
* @param {Number} len The length of the chunk
* @param {Any} fallback The value to use if the input sequence is too short.
* @returns {Iterator} Sequence of lists
*/
const chunkifyWithFallback = curry('chunkifyWithFallback', (seq, len, fallback) => pipe(
chunkifyShort(seq, len),
map((chunk) => {
if (size(chunk) === len) {
return chunk;
} else {
return take(concat(chunk, repeat(fallback)), len);
}
}),
));

/**
* Calculate the cartesian product of the given sequences.
*
@@ -1728,6 +1815,9 @@ module.exports = {
slidingWindow,
trySlidingWindow,
lookahead,
chunkifyShort,
chunkify,
chunkifyWithFallback,
cartesian,
cartesian2,
mod,
@@ -15,14 +15,14 @@

const assert = require('assert');
const {
and, plus, or, mul, not,
and, plus, or, mul, not, curry,
size, TraitNotImplemented, _typedArrays,
iter, range, range0, repeat, repeatFn, extend, extend1, flattenTree,
IteratorEnded, next, tryNext, nth, first, second, last, tryNth, tryFirst,
trySecond, tryLast, seqEq, each, find, tryFind, contains, count, list,
uniq, join, dict, obj, into, foldl, foldr, any, all, sum, product, map,
filter, reject, reverse, enumerate, trySkip, skip, skipWhile, tryTake,
takeShort, takeWithFallback,
takeShort, takeWithFallback, chunkifyShort, chunkify, chunkifyWithFallback,
take, takeWhile, takeUntilVal, takeDef, flat, concat, prepend, append,
mapSort, zipLeast, zip, zipLongest, zipLeast2, zip2, zipLongest2,
slidingWindow, trySlidingWindow, lookahead, mod, union, union2,
@@ -426,6 +426,22 @@ it('lookahead', () => {
ck([42, 23], 0, null, [[42], [23]]);
});

it('chunkify/chunkifyShort/chunkifyWithFallback', () => {
const withFallback = curry('withFallback', (seq, len) => chunkifyWithFallback(len, null)(seq));
each([chunkify, withFallback, chunkifyShort], (fn) => {
ckEqSeq(fn(2)([1, 2, 3, 4]), [[1, 2], [3, 4]]);
ckEqSeq(fn(2)([]), []);
ckEqSeq(fn(1)([1, 2, 3, 4]), [[1], [2], [3], [4]]);
ckEqSeq(fn(1)([]), []);
ckEqSeq(fn(0)([1, 2, 3, 4]), []);
ckEqSeq(fn(0)([]), []);
});

ckEqSeq(chunkifyShort([1, 2, 3, 4], 3), [[1, 2, 3], [4]]);
ckEqSeq(chunkifyWithFallback([1, 2, 3, 4], 3, null), [[1, 2, 3], [4, null, null]]);
ckThrows(IteratorEnded, () => list(chunkify([1, 2, 3, 4], 3)));
});

it('cartesian', () => {
ckEqSeq(cartesian([]), []);
ckEqSeq(cartesian([[]]), []);

0 comments on commit 9ff9603

Please sign in to comment.
You can’t perform that action at this time.