I am aware of this question, simplest code for array intersection but all the solutions presume the number of arrays is two, which cannot be certain in my case.
I ha
Using a combination of ideas from several contributors and the latest ES6 goodness, I arrived at
const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];
Array.prototype.intersect = function intersect(a, ...b) {
const c = function (a, b) {
b = new Set(b);
return a.filter((a) => b.has(a));
};
return undefined === a ? this : intersect.call(c(this, a), ...b);
};
console.log(array1.intersect(array2, array3, array4));
// ["Lorem"]
Intersection of a variable number of arrays.
This is how I do it:
function getArraysIntersection(list1, list2, ...otherLists) {
const result = [];
for (let i = 0; i < list1.length; i++) {
let item1 = list1[i];
let found = false;
for (var j = 0; j < list2.length && !found; j++) {
found = item1 === list2[j];
}
if (found === true) {
result.push(item1);
}
}
if (otherLists.length) {
return getArraysIntersection(result, otherLists.shift(), ...otherLists);
}
else {
return result;
}
}
SNIPPET
function getArraysIntersection(list1, list2, ...otherLists) {
const result = [];
for (let i = 0; i < list1.length; i++) {
let item1 = list1[i];
let found = false;
for (var j = 0; j < list2.length && !found; j++) {
found = item1 === list2[j];
}
if (found === true) {
result.push(item1);
}
}
if (otherLists.length) {
return getArraysIntersection(result, otherLists.shift(), ...otherLists);
}
else {
return result;
}
}
const a = {label: "a", value: "value_A"};
const b = {label: "b", value: "value_B"};
const c = {label: "c", value: "value_C"};
const d = {label: "d", value: "value_D"};
const e = {label: "e", value: "value_E"};
const arr1 = [a,b,c];
const arr2 = [a,b,c];
const arr3 = [c];
const t0 = performance.now();
const intersection = getArraysIntersection(arr1,arr2,arr3);
const t1 = performance.now();
console.log('This took t1-t0: ' + (t1-t0).toFixed(2) + ' ms');
console.log(intersection);
I wrote a helper function for this:
function intersection() {
var result = [];
var lists;
if(arguments.length === 1) {
lists = arguments[0];
} else {
lists = arguments;
}
for(var i = 0; i < lists.length; i++) {
var currentList = lists[i];
for(var y = 0; y < currentList.length; y++) {
var currentValue = currentList[y];
if(result.indexOf(currentValue) === -1) {
var existsInAll = true;
for(var x = 0; x < lists.length; x++) {
if(lists[x].indexOf(currentValue) === -1) {
existsInAll = false;
break;
}
}
if(existsInAll) {
result.push(currentValue);
}
}
}
}
return result;
}
Use it like this:
intersection(array1, array2, array3, array4); //["Lorem"]
Or like this:
intersection([array1, array2, array3, array4]); //["Lorem"]
Full code here
UPDATE 1
A slightly smaller implementation here using filter
This can be done pretty succinctly if you fancy employing some recursion and the new ES2015 syntax:
const array1 = ["Lorem", "ipsum", "dolor"];
const array2 = ["Lorem", "ipsum", "quick", "brown", "foo"];
const array3 = ["Jumps", "Over", "Lazy", "Lorem"];
const array4 = [1337, 420, 666, "Lorem"];
const arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]];
// Filter xs where, for a given x, there exists some y in ys where y === x.
const intersect2 = (xs,ys) => xs.filter(x => ys.some(y => y === x));
// When there is only one array left, return it (the termination condition
// of the recursion). Otherwise first find the intersection of the first
// two arrays (intersect2), then repeat the whole process for that result
// combined with the remaining arrays (intersect). Thus the number of arrays
// passed as arguments to intersect is reduced by one each time, until
// there is only one array remaining.
const intersect = (xs,ys,...rest) => ys === undefined ? xs : intersect(intersect2(xs,ys),...rest);
console.log(intersect(array1, array2, array3, array4));
console.log(intersect(...arrayOfArrays));
// Alternatively, in old money,
var intersect2ES5 = function (xs, ys) {
return xs.filter(function (x) {
return ys.some(function (y) {
return y === x;
});
});
};
// Changed slightly from above, to take a single array of arrays,
// which matches the underscore.js approach in the Q., and is better anyhow.
var intersectES5 = function (zss) {
var xs = zss[0];
var ys = zss[1];
var rest = zss.slice(2);
if (ys === undefined) {
return xs;
}
return intersectES5([intersect2ES5(xs, ys)].concat(rest));
};
console.log(intersectES5([array1, array2, array3, array4]));
console.log(intersectES5(arrayOfArrays));
const intersect = (arrayA, arrayB) => {
return arrayA.filter(elem => arrayB.includes(elem));
};
const intersectAll = (...arrays) => {
if (!Array.isArray(arrays) || arrays.length === 0) return [];
if (arrays.length === 1) return arrays[0];
return intersectAll(intersect(arrays[0], arrays[1]), ...arrays.slice(2));
};
For anyone confused by this in the future,
_.intersection.apply(_, arrayOfArrays)
Is in fact the most elegant way to do this. But:
var arrayOfArrays = [[43, 34343, 23232], [43, 314159, 343], [43, 243]];
arrayOfArrays = _.intersection.apply(_, arrayOfArrays);
Will not work! Must do
var differentVariableName = _.intersection.apply(_,arrayOfArrays);