The question has been asked for many languages, yet not for javascript.
Ruby has the method Enumerable#each_cons
which look like that:
puts (0..5).each_cons(2).to_a
# [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]
puts (0..5).each_cons(3).to_a
# [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
How could I have a similar method in javascript for Array
?
The question has been asked for many languages, yet not for javascript.
Ruby has the method Enumerable#each_cons
which look like that:
puts (0..5).each_cons(2).to_a
# [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]
puts (0..5).each_cons(3).to_a
# [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
How could I have a similar method in javascript for Array
?
3 Answers
Reset to default 7Here is a function that will do it (ES6+):
// functional approach
const eachCons = (array, num) => {
return Array.from({ length: array.length - num + 1 },
(_, i) => array.slice(i, i + num))
}
// prototype overriding approach
Array.prototype.eachCons = function(num) {
return Array.from({ length: this.length - num + 1 },
(_, i) => this.slice(i, i + num))
}
const array = [0,1,2,3,4,5]
const log = data => console.log(JSON.stringify(data))
log(eachCons(array, 2))
log(eachCons(array, 3))
log(array.eachCons(2))
log(array.eachCons(3))
You have to guess the length of the resulting array (n = length - num + 1
), and then you can take advantage of JavaScript's array.slice
To get the chunks you need, iterating n
times.
You could take the length, build a new array and map the sliced array with Array.from
and the build in mapper.
Number.prototype[Symbol.iterator] = function* () {
for (var i = 0; i < this; i++) yield i;
};
Array.prototype.eachCons = function (n) {
return Array.from({ length: this.length - n + 1}, (_, i) => this.slice(i, i + n));
}
console.log([...10].eachCons(2));
console.log([...10].eachCons(3));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here is a single line solution relying on function generators. Perhaps slightly different, but still worth to try out.
I've also added to the prototype, not sure why you would do that, but still..
This solution doesn't require ES6, it can be used with ES5 as well, with a bit of care for IE that doesn't support function generators at all.
function* eachCons(arr, num) {
for (let counter = 0; counter <= arr.length - num; counter++) yield arr.slice(counter, counter + num);
}
Array.prototype.eachCons = function* (num) {
for (let counter = 0; counter <= this.length - num; counter++) yield this.slice(counter, counter + num);
}
const array = [0,1,2,3,4,5];
const log = data => console.log(JSON.stringify(data))
log([...eachCons(array, 2)]);
log([...eachCons(array, 3)]);
// Iterable way
for (let [...pack] of eachCons(array, 2)) {
console.log('pack is', pack);
}
// Prototype...
for (let [...pack] of array.eachCons(2)) {
console.log('pack is', pack);
}