Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate an array as a pair (current, next) in JavaScript

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 the same problem, but I'd like to do it in JavaScript in the cleanest way possible, perhaps using lodash.

It is easy to do this with a simple for loop, but it doesn't feel very elegant.

for (var i = 0; i < arr.length - 1; i++) {
  var currentElement = arr[i];
  var nextElement = arr[i + 1];
}

Lodash almost can do this:

_.forEach(_.zip(arr, _.rest(arr)), function(tuple) {
  var currentElement = tuple[0];
  var nextElement = tuple[1];
})

The subtle problem with this that on the last iteration, nextElement will be undefined.

Of course the ideal solution would simply be a pairwise lodash function that only looped as far as necessary.

_.pairwise(arr, function(current, next) {
  // do stuff 
});

Are there any existing libraries that do this already? Or is there another nice way to do pairwise iteration in JavaScript that I haven't tried?


Clarification: If arr = [1, 2, 3, 4], then my pairwise function would iterate as follows: [1, 2], [2, 3], [3, 4], not [1, 2], [3, 4]. This is what the OP was asking about in the original question for Python.

like image 481
therealrootuser Avatar asked Aug 12 '15 18:08

therealrootuser


People also ask

How do you iterate through an array of key value pairs in JavaScript?

keys() method was introduced in ES6. It takes the object that you want to iterate over as an argument and returns an array containing all properties names (or keys). You can then use any of the array looping methods, such as forEach(), to iterate through the array and retrieve the value of each property.

How do you get a pair from an array?

In order to find all the possible pairs from the array, we need to traverse the array and select the first element of the pair. Then we need to pair this element with all the elements in the array from index 0 to N-1. Below is the step by step approach: Traverse the array and select an element in each traversal.

How do you cycle through an array?

Iterating over an array You can iterate over an array using for loop or forEach loop. Using the for loop − Instead on printing element by element, you can iterate the index using for loop starting from 0 to length of the array (ArrayName. length) and access elements at each index.


3 Answers

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)
like image 126
juvian Avatar answered Oct 12 '22 20:10

juvian


In Ruby, this is called each_cons (each consecutive):

(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]]
like image 41
chocolateboy Avatar answered Oct 12 '22 21:10

chocolateboy


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]]
like image 6
Oliver Joseph Ash Avatar answered Oct 12 '22 21:10

Oliver Joseph Ash