I'm given an array of entries in javascript, such as :
var entries = ["cat", "dog", "chicken", "pig"];
I'd now like to iterate over all unique pairwise binations of them. In this example, I'd like to see:
("cat", "dog"),
("cat", "chicken"),
...
In other languages, like scala, this is super easy. You just do
entriesbinations(2)
is there a similar method or function in a library for javascript? Or do I just have to write it myself the ugly way with nested loops?
I'm given an array of entries in javascript, such as :
var entries = ["cat", "dog", "chicken", "pig"];
I'd now like to iterate over all unique pairwise binations of them. In this example, I'd like to see:
("cat", "dog"),
("cat", "chicken"),
...
In other languages, like scala, this is super easy. You just do
entries.binations(2)
is there a similar method or function in a library for javascript? Or do I just have to write it myself the ugly way with nested loops?
Share Improve this question edited Aug 24, 2012 at 6:35 xdazz 161k38 gold badges253 silver badges278 bronze badges asked Aug 24, 2012 at 6:30 fozziethebeatfozziethebeat 1,1802 gold badges12 silver badges28 bronze badges 1- Yes, you have to write it yourself. – xdazz Commented Aug 24, 2012 at 6:39
6 Answers
Reset to default 6var arr = ["cat","dog","chicken","pig"].map(function(item,i,arr) {
return arr.map(function(_item) { if( item != _item) return [item, _item];});
});
This will return the expected results. There are caveats, it does not work in older browsers without shims.
Also the duplicate value is 'undefined' instead of there being 4 arrays of 3. I'm sure there is a more graceful way to handle this.
Array.prototype.map() - MDN
edit
this will give you the proper pairwise binations.
var arr = ["cat","dog","chicken","pig"].map(function(item,i,arr) {
var tmp = arr.map(function(_item) { if( item != _item) return [item, _item];});
return tmp.splice(tmp.indexOf(undefined),1), tmp;
});
Array splice method - MDN
and here is a more readable version of the same code.
var myArray = ["cat", "dog", "chicken", "pig"];
var pairwise = myArray.map(function(item, index, originalArray) {
var tmp = originalArray.map(function(_item) {
if (item != _item) {
return [item, _item];
}
});
tmp.splice(tmp.indexOf(undefined), 1); // because there is now one undefined index we must remove it.
return tmp;
});
Not as far as I know. I think you have to stick to nested loops.
A similar question has been asked here: Output each bination of an array of numbers with javascript maybe you can find an answer there.
With ES6 syntax, one can use a shorter version of @rlemon's answer:
["cat","dog","chicken","pig"].sort().reduce(
(acc, item, i, arr) => acc.concat(
arr.slice(i + 1).map(_item => [item, _item])
),
[])
This takes care of undefined
s, and also outputs only unique binations, as per OP's question.
After reviewing the question, this answer doesn't correctly solve the question. The question asks for all binations, but the function below bines all adjacent even and odd indexes of the array.
Here is a pairwise implementation I did using reduce
function pairwise(arr) {
return arr.reduce(function(acc, current, index) {
var isFirstPair = (index % 2) === 0;
if (isFirstPair) {
acc.push([current]);
} else {
lastElement = acc[acc.length - 1];
lastElement.push(current);
}
return acc;
}, []);
};
var nums = [1,2,3,4,5,6];
var res = pairwise(nums);
res.forEach(function(elem) {
console.log(elem);
});
Returns:
[
[1, 2]
[3, 4]
[5, 6]
]
Here's a generic TypeScript implementation (you can get the pure JS by removing the types):
// Returns an array of size
const sizedArray = (n: number): null[] => Array(n).fill(null);
// calls the callback n times
const times = (n: number, cb: () => void): void => {
while (0 < n--) {
cb();
}
};
// Fills up the array with the return values of subsequent calls of cb
const fillWithCb = <T>(n: number, cb: () => T): T[] => sizedArray(n).map(cb);
// Generic to produce pairwise, 3 element wise etc..
const nWise = (n: number): (<T>(array: T[]) => T[][]) => <T>(
array: T[]
): T[][] => {
const 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)
);
};
// curried nWise with 2 -> pairWise
export const pairWise = nWise(2);
The most effective and simple solution can be reduced and slice. However, if you just want to get values. You can use a generator.
// Util class
function pairWise(arr) {
return {
[Symbol.iterator]: function *() {
for(let i =0; i< arr.length; i= i+2)
yield arr.slice(i, i+2)
}
}
}
// How to use it
for(ent of pairWise([1,2,3,4,5,6, 7])){
console.log(ent)
}
// Output
/*
[ 1, 2 ]
[ 3, 4 ]
[ 5, 6 ]
[ 7 ]
*/