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
Lodash does have a method that allows you to do this: https://lodash.com/docs#chunk
_.chunk(array, 2).forEach(function(pair) {
var first = pair[0];
var next = pair[1];
console.log(first, next)
})
This answer is inspired by an answer I saw to a similar question but in Haskell: https://stackoverflow.com/a/4506000/5932012
We can use helpers from Lodash to write the following:
const zipAdjacent = function<T> (ts: T[]): [T, T][] {
return zip(dropRight(ts, 1), tail(ts));
};
zipAdjacent([1,2,3,4]); // => [[1,2], [2,3], [3,4]]
(Unlike the Haskell equivalent, we need dropRight
because Lodash's zip
behaves differently to Haskell's`: it will use the length of the longest array instead of the shortest.)
The same in Ramda:
const zipAdjacent = function<T> (ts: T[]): [T, T][] {
return R.zip(ts, R.tail(ts));
};
zipAdjacent([1,2,3,4]); // => [[1,2], [2,3], [3,4]]
Although Ramda already has a function that covers this called aperture. This is slightly more generic because it allows you to define how many consecutive elements you want, instead of defaulting to 2:
R.aperture(2, [1,2,3,4]); // => [[1,2], [2,3], [3,4]]
R.aperture(3, [1,2,3,4]); // => [[1,2,3],[2,3,4]]
d3.js provides a built-in version of what is called in certain languages a sliding
:
console.log(d3.pairs([1, 2, 3, 4])); // [[1, 2], [2, 3], [3, 4]]
<script src="http://d3js.org/d3.v5.min.js"></script>
# d3.pairs(array[, reducer]) <>
For each adjacent pair of elements in the specified array, in order, invokes the specified reducer function passing the element i and element i - 1. If a reducer is not specified, it defaults to a function which creates a two-element array for each pair.
We can wrap Array.reduce a little to do this, and keep everything clean. Loop indices / loops / external libraries are not required.
If the result is required, just create an array to collect it.
function pairwiseEach(arr, callback) {
arr.reduce((prev, current) => {
callback(prev, current)
return current
})
}
function pairwise(arr, callback) {
const result = []
arr.reduce((prev, current) => {
result.push(callback(prev, current))
return current
})
return result
}
const arr = [1, 2, 3, 4]
pairwiseEach(arr, (a, b) => console.log(a, b))
const result = pairwise(arr, (a, b) => [a, b])
const output = document.createElement('pre')
output.textContent = JSON.stringify(result)
document.body.appendChild(output)
Simply use forEach with all its parameters for this:
yourArray.forEach((current, idx, self) => {
if (let next = self[idx + 1]) {
//your code here
}
})
Here's a generic functional solution without any dependencies:
const nWise = (n, array) => {
iterators = Array(n).fill()
.map(() => array[Symbol.iterator]());
iterators
.forEach((it, index) => Array(index).fill()
.forEach(() => it.next()));
return Array(array.length - n + 1).fill()
.map(() => (iterators
.map(it => it.next().value);
};
const pairWise = (array) => nWise(2, array);
I know doesn't look nice at all but by introducing some generic utility functions we can make it look a lot nicer:
const sizedArray = (n) => Array(n).fill();
I could use sizedArray
combined with forEach
for times
implementation, but that'd be an inefficient implementation. IMHO it's ok to use imperative code for such a self-explanatory function:
const times = (n, cb) => {
while (0 < n--) {
cb();
}
}
If you're interested in more hardcore solutions, please check this answer.
Unfortunately Array.fill
only accepts a single value, not a callback. So Array(n).fill(array[Symbol.iterator]())
would put the same value in every position. We can get around this the following way:
const fillWithCb = (n, cb) => sizedArray(n).map(cb);
The final implementation:
const nWise = (n, array) => {
iterators = fillWithCb(n, () => array[Symbol.iterator]());
iterators.forEach((it, index) => times(index, () => it.next()));
return fillWithCb(
array.length - n + 1,
() => (iterators.map(it => it.next().value),
);
};
By changing the parameter style to currying, the definition of pairwise would look a lot nicer:
const nWise = n => array => {
iterators = fillWithCb(n, () => array[Symbol.iterator]());
iterators.forEach((it, index) => times(index, () => it.next()));
return fillWithCb(
array.length - n + 1,
() => iterators.map(it => it.next().value),
);
};
const pairWise = nWise(2);
And if you run this you get:
> pairWise([1, 2, 3, 4, 5]);
// [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ], [ 4, 5 ] ]