In the question Iterate a list as pair (current, next) in Python, the OP is interested in iterating a Python list as a series of current, next pairs. I have th
Here's my approach, using Array.prototype.shift:
Array.prototype.pairwise = function (callback) {
const copy = [].concat(this);
let next, current;
while (copy.length) {
current = next ? next : copy.shift();
next = copy.shift();
callback(current, next);
}
};
This can be invoked as follows:
// output:
1 2
2 3
3 4
4 5
5 6
[1, 2, 3, 4, 5, 6].pairwise(function (current, next) {
console.log(current, next);
});
So to break it down:
while (this.length) {
Array.prototype.shift directly mutates the array, so when no elements are left, length will obviously resolve to 0. This is a "falsy" value in JavaScript, so the loop will break.
current = next ? next : this.shift();
If next has been set previously, use this as the value of current. This allows for one iteration per item so that all elements can be compared against their adjacent successor.
The rest is straightforward.
Hope it helps someone! (and likes)
arr = [1, 2, 3, 4];
output = [];
arr.forEach((val, index) => {
if (index < (arr.length - 1) && (index % 2) === 0) {
output.push([val, arr[index + 1]])
}
})
console.log(output);
Another solution using iterables and generator functions:
function * pairwise (iterable) {
const iterator = iterable[Symbol.iterator]()
let current = iterator.next()
let next = iterator.next()
while (!current.done) {
yield [current.value, next.value]
current = next
next = iterator.next()
}
}
console.log(...pairwise([]))
console.log(...pairwise(['apple']))
console.log(...pairwise(['apple', 'orange', 'kiwi', 'banana']))
console.log(...pairwise(new Set(['apple', 'orange', 'kiwi', 'banana'])))
Advantages:
Just make the "ugly" part into a function and then it looks nice:
arr = [1, 2, 3, 4];
function pairwise(arr, func){
for(var i=0; i < arr.length - 1; i++){
func(arr[i], arr[i + 1])
}
}
pairwise(arr, function(current, next){
console.log(current, next)
})
You can even slightly modify it to be able to make iterate all i, i+n pairs, not just the next one:
function pairwise(arr, func, skips){
skips = skips || 1;
for(var i=0; i < arr.length - skips; i++){
func(arr[i], arr[i + skips])
}
}
pairwise([1, 2, 3, 4, 5, 6, 7], function(current,next){
console.log(current, next) // displays (1, 3), (2, 4), (3, 5) , (4, 6), (5, 7)
}, 2)
My two cents. Basic slicing, generator version.
function* generate_windows(array, window_size) {
const max_base_index = array.length - window_size;
for(let base_index = 0; base_index <= max_base_index; ++base_index) {
yield array.slice(base_index, base_index + window_size);
}
}
const windows = generate_windows([1, 2, 3, 4, 5, 6, 7, 8, 9], 3);
for(const window of windows) {
console.log(window);
}
In Ruby, this is called each_cons:
(1..5).each_cons(2).to_a # => [[1, 2], [2, 3], [3, 4], [4, 5]]
It was proposed for Lodash, but rejected; however, there's an each-cons module on npm:
const eachCons = require('each-cons')
eachCons([1, 2, 3, 4, 5], 2) // [[1, 2], [2, 3], [3, 4], [4, 5]]
There's also an aperture function in Ramda which does the same thing:
const R = require('ramda')
R.aperture(2, [1, 2, 3, 4, 5]) // [[1, 2], [2, 3], [3, 4], [4, 5]]