I need to call function with all avaliable pairs of array elements. Like this:
[1, 2, 3].pairs(function (pair) {
console.log(pair); //[1,2], [1,3], [2,3]
});
I need to call function with all avaliable pairs of array elements. Like this:
[1, 2, 3].pairs(function (pair) {
console.log(pair); //[1,2], [1,3], [2,3]
});
You should try to show us that you've solved the problem yourself instead of just asking us for the answer, but it was an interesting problem, so here:
Array.prototype.pairs = function (func) {
for (var i = 0; i < this.length - 1; i++) {
for (var j = i; j < this.length - 1; j++) {
func([this[i], this[j+1]]);
}
}
}
var list = [1, 2, 3];
list.pairs(function(pair){
console.log(pair); // [1,2], [1,3], [2,3]
});
Thanks to the continuous evolvement of the ECMAScript standard ..
let pairs = (arr) => arr.map( (v, i) => arr.slice(i + 1).map(w => [v, w]) ).flat();
pairs([1, 2, 3, 4, 5]);
function pairs(arr) {
var res = [],
l = arr.length;
for(var i=0; i<l; ++i)
for(var j=i+1; j<l; ++j)
res.push([arr[i], arr[j]]);
return res;
}
pairs([1, 2, 3]).forEach(function(pair){
console.log(pair);
});
Here is a variant in ES6 style without mutations:
const pairsOfArray = array => (
array.reduce((acc, val, i1) => [
...acc,
...new Array(array.length - 1 - i1).fill(0)
.map((v, i2) => ([array[i1], array[i1 + 1 + i2]]))
], [])
)
const pairs = pairsOfArray(['a', 'b', 'c', 'd', 'e'])
console.log(pairs)
// => [['a','b'], ['a','c'], ['a','d'],['a','e'],['b','c'],['b','d'],['b','e'],['c','d'],['c','e'],['d','e']]
With flatMap
now available in ECMAScript, there's a really simple and readable option to find pairs of items in a list in Javascript with no loops:
const pairs = (a) => {
return a.flatMap( (x) => {
return a.flatMap( (y) => {
return (x != y) ? [[x,y]] : []
});
});
}
calling pairs([1,2,3])
will output:
[ [ 1, 2 ], [ 1, 3 ], [ 2, 1 ], [ 2, 3 ], [ 3, 1 ], [ 3, 2 ] ]
Simple, readable and functional.
EDIT: I originally read this question as "how to get all pairs" which I assumed included reversed pairs, which the above example does. To return the list without the reversed order pairs, we can take these out with reduce()
:
const isInArray = (a, value) => {
if (
a.map((x) => {
if (x.toString() == value.toString()) return true;
}).includes(true)
){
return true;
}
};
const reducedPairs = (a) => {
return a.flatMap( (x) => {
return a.flatMap( (y) => {
return (x != y) ? [[x,y]] : []
});
}).reduce( (unique, current) => {
if (!isInArray(unique, current.slice().reverse())) unique.push(current);
return unique;
}, []);
}
Note that this uses string comparisons to check for array equality since [1,2] == [1,2]
is false
. This works for the use case in the original question, but for a more complex example an alternative method of checking for duplicates may be required.
Here is the cleanest solution that I could find using ES6. It generates unique pairs based on the index and using the flatMap function.
const uniquePairs = (arr) =>
arr.flatMap((item1, index1) =>
arr.flatMap((item2, index2) =>
(index1 > index2) ? [[item1,item2]] : []
)
)
uniquePairs([1,2,3])
// [[2, 1], [3, 1], [3, 2]]
flatMap
- returns elements into one array, and has the benefit of being able to remove empty arrays entirely. This is what allows our ternary with a value of []
to just disappear!
Like map
, it can return the index, and by comparing the index of both items, we can avoid duplicates (the 1st index must be greater than the 2nd for us to add an element).
The ternary lets us do a comparison and returns an empty array if false (which get's completely ignored by the 2nd flatMap).
By changing each flatMap
into a map
you can have a better idea of what each flatMap
is accomplishing- so I encourage you to try altering it!
In case you're looking for reversed pairs as well - going off of @Oriol's answer above - here's a version that includes all original pairs + all original pairs reversed:
function allPairs (arr) {
let pairs = [];
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
pairs.push([arr[i], arr[j]]);
}
}
let copy = pairs;
pairs = JSON.stringify(pairs);
let reversed = [];
copy.forEach((value) => {
reversed.push(value.reverse());
})
let final = [];
final.push(JSON.parse(pairs).concat(reversed));
return final[0];
}
console.log(allPairs([1, 2, 3, 4, 5]));