How to calculate intersection of multiple arrays in JavaScript? And what does [equal: function] mean?

I know this question, the simplest code for intersecting an array , but all solutions assume that the number of arrays is two, which cannot be sure in my case.

I have divs on a data page that contain arrays. I want to find values ​​common to all arrays. I don't know how many div / arrays I will have in advance. What is the best way to calculate the values ​​common to all arrays?

var array1 = ["Lorem", "ipsum", "dolor"]; var array2 = ["Lorem", "ipsum", "quick", "brown", "foo"]; var array3 = ["Jumps", "Over", "Lazy", "Lorem"]; var array4 = [1337, 420, 666, "Lorem"]; //Result should be ["Lorem"]; 

I found another solution elsewhere using Underscore.js.

 var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]]; _.intersection.apply(_, arrayOfArrays) //Result is [43] 

I tested this with simple dummy data at the end and it seemed to work. But for some reason, some of the arrays I create that contain simple strings also automatically include the added value, "equals: function":

 ["Dummy1", "Dummy2", "Dummy3", equals: function] 

And whenever I use the intersection method Underscore.js, in an array of arrays I always get [equals: function] in dev tools, and not if "Dummy3" is common to all arrays - ["Dummy3"].

So TL; DR is there another solution to traverse the array that suits my case? And can anyone explain what [equals: function] means here? When I expand an element in dev tools, it creates an empty array and a list of available methods on arrays (pop, push, shift, etc.), But all these methods disappear, and the equals: function is highlighted.

+11
source share
10 answers

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

+6
source

You can simply use Array#reduce with Array#filter Array#includes and Array#includes .

 var array1 = ["Lorem", "ipsum", "dolor"], array2 = ["Lorem", "ipsum", "quick", "brown", "foo"], array3 = ["Jumps", "Over", "Lazy", "Lorem"], array4 = [1337, 420, 666, "Lorem"], data = [array1, array2, array3, array4], result = data.reduce((a, b) => a.filter(c => b.includes(c))); console.log(result); 
+8
source

This can be done quite succinctly if you want to use 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)); 
+7
source

Using a combination of ideas from several participants and the latest kindness of ES6, I came to

 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"] 
+3
source

Your code with _lodash is working fine.

As you can say in this script:

this code:

 var arrayOfArrays = [[4234, 2323, 43], [1323, 43, 1313], [23, 34, 43]]; var a = _.intersection.apply(_, arrayOfArrays); console.log(a); console.log(a.length); 

It will display:

 [42] 1 

Maybe you see

equals: function

because you are using a debugger.

Try just printing the array using console.log , you will only get 42.

+1
source

For everyone whom this confuses in the future,

 _.intersection.apply(_, arrayOfArrays) 

This is actually 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! Need to do

 var differentVariableName = _.intersection.apply(_,arrayOfArrays); 
0
source

Lodash pure:

 _.keys(_.pickBy(_.groupBy(_.flatten(arrays)), function (e) {return e.length > 1})) 

Lodash with plain js:

 var elements = {}, duplicates = {}; _.each(arrays, function (array) { _.each(array, function (element) { if (!elements[element]) { elements[element] = true; } else { duplicates[element] = true; } }); }); _.keys(duplicates); 
0
source

A small recursive divide and conquer solution that does not depend on es6 or any library.

It takes an array of arrays, which makes the code shorter and allows you to pass arguments using map.

 function intersection(a) { if (a.length > 2) return intersection([intersection(a.slice(0, a.length / 2)), intersection(a.slice(a.length / 2))]); if (a.length == 1) return a[0]; return a[0].filter(function(item) { return a[1].indexOf(item) !== -1; }); } var list1 = [ 'a', 'b', 'c' ]; var list2 = [ 'd', 'b', 'e' ]; var list3 = [ 'f', 'b', 'e' ]; console.log(intersection([list1, list2, list3])); 
0
source

Arg0n's answer is great, but just in case anyone is looking for intersection of arrays of objects, I slightly modified Arg0n's answer to deal with it.

 function getIntersectedData() { var lists = [[{a:1,b:2},{a:2,b:2}],[{a:1,b:2},{a:3,b:3}],[{a:1,b:2},{a:4,b:4}]]; var result = []; 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 (customIndexOf(result,currentValue)) { var existsInAll = true; for (var x = 0; x < lists.length; x++) { if(customIndexOf(lists[x],currentValue)){ existsInAll = false; break; } } if (existsInAll) { result.push(currentValue); } } } return result; } } function customIndexOf(array,value){ var notFind = true; array.forEach(function(element){ if(element.a === value.a){ notFind = false; } }); return notFind; } 
0
source

I manage to do this using reduce call:

 var intersected = intersect([[1, 2, 3], [2, 3, 4], [3, 4, 5]]); console.log(intersected); // [3] function intersect(arrays) { if (0 === arrays.length) { return []; } return arrays.reduce((intersection, array) => { return intersection.filter(intersectedItem => array.some(item => intersectedItem === item)); }, arrays[0]); } 
0
source

All Articles