150

I have two arrays, and I want to be able to compare the two and only return the values that match. For example both arrays have the value cat so that is what will be returned. I haven't found anything like this. What would be the best way to return similarities?

var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];

//if value in array1 is equal to value in array2 then return match: cat
Muhammad Musavi
  • 2,512
  • 2
  • 22
  • 35
Daniel
  • 4,202
  • 11
  • 50
  • 68

13 Answers13

476

You can use :

const intersection = array1.filter(element => array2.includes(element));
jota3
  • 5,389
  • 2
  • 13
  • 22
  • 20
    This looks like the simplest and most concise answer. Not sure why it's not marked as being the right one. – Burke Holland Aug 15 '18 at 11:56
  • 3
    That is because not all browsers will support it, unless you use a polyfill: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes – Andrei Drynov Oct 01 '18 at 11:58
  • 1
    As of late April 2019, only IE doesn't provide support. – absay Apr 23 '19 at 18:01
  • 7
    ```const intersection = array1.filter(element => array2.indexOf(element) !== -1);``` without a polyfill. – simmer May 08 '19 at 18:00
  • `.includes()` is ES2016....meaning your ES6 transpiler will not transpile it. – dman Jul 19 '19 at 14:23
  • @jota3 Hi, but how to keep the values unique in intersection. If array1 or array2 contains "cat" twice then my intersection array will also have "cat" 2 times. How to prevent that? – Vibhav Chaddha Oct 17 '19 at 11:32
  • 9
    @Learner from ES6 you can use Set to filter out duplicated values and spread its values in an array like this : `const intersection = [...new Set(array1.filter(element => array2.includes(element)))];` – jota3 Oct 17 '19 at 18:58
  • 1
    The really shocking part about this answer is that it's faster than the other solutions. A benchmark of phant0m, jeremy and jota3's answers shows consistent results. Measured in nanoseconds, phant0m: 107600, jeremy: 128300, jota3: 96800. The array's were a 91 5 letter word array compared to a 237 5 letter word array. No duplicates. – Zei Oct 20 '22 at 10:28
65

Naturally, my approach was to loop through the first array once and check the index of each value in the second array. If the index is > -1, then push it onto the returned array.

​Array.prototype.diff = function(arr2) {
    var ret = [];
    for(var i in this) {   
        if(arr2.indexOf(this[i]) > -1){
            ret.push(this[i]);
        }
    }
    return ret;
};

​ My solution doesn't use two loops like others do so it may run a bit faster. If you want to avoid using for..in, you can sort both arrays first to reindex all their values:

Array.prototype.diff = function(arr2) {
    var ret = [];
    this.sort();
    arr2.sort();
    for(var i = 0; i < this.length; i += 1) {
        if(arr2.indexOf(this[i]) > -1){
            ret.push(this[i]);
        }
    }
    return ret;
};

Usage would look like:

var array1 = ["cat", "sum","fun", "run", "hut"];
var array2 = ["bat", "cat","dog","sun", "hut", "gut"];

console.log(array1.diff(array2));

If you have an issue/problem with extending the Array prototype, you could easily change this to a function.

var diff = function(arr, arr2) {

And you'd change anywhere where the func originally said this to arr2.

jeremy
  • 9,965
  • 4
  • 39
  • 59
  • 5
    `.indexOf()` just moves the loop. The method loops through the target array internally. (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf) – Jeremy J Starcher Sep 15 '12 at 01:16
  • the `.indexOf()` function is probably faster than looping through all the array like done in the compatibility alternative. – jeremy Sep 15 '12 at 01:19
  • Is indexOf() smart enough to use a binary search after the sort? Otherwise, this is O(N^2) since you are essentially doing nested looping due to indexOf() performing a linear scan. Even without that issue, why incur the linearithmic cost of sort when you can do this in linear time using an object as a hash table? – ChaseMedallion Sep 15 '12 at 01:19
  • I've not heard of any ECMASCript engine that switches to a binary search on sorted arrays. Would be an interesting optimization, including carrying a 'sorted' flag around with the array, but I wonder if there'd be enough call for it. – Jeremy J Starcher Sep 15 '12 at 01:22
  • This is a bit late, but looks like the latest Chrome versions at least have much faster indexOf: http://jsperf.com/jquery-inarray-vs-underscore-indexof/43 – Andrew Odri Feb 06 '15 at 19:20
  • Jeremy, great solution. I was debating myself between using two nested for loops vs. for-in with an embedded `indexOf()` lookup. However, I couldn't justify which of the two to use - both are readable to me, but one is more functional. My question to you is, how do you suppose your solution is faster when indexOf() uses a while loop anyways to do a strict comparison? Essentially, indexOf() just adds a layer of abstraction imo. See the indexOf polyfill code: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf – puiu Dec 15 '15 at 18:05
35

I found a slight alteration on what @jota3 suggested worked perfectly for me.

var intersections = array1.filter(e => array2.indexOf(e) !== -1);

Hope this helps!

Fred Read
  • 453
  • 5
  • 8
  • 8
    It means you were using a javascript version anterior to ES2016 in which includes() has been added. indexOf() will work with any version. – jota3 Apr 05 '18 at 10:01
17

This function runs in O(n log(n) + m log(m)) compared to O(n*m) (as seen in the other solutions with loops/indexOf) which can be useful if you are dealing with lots of values.

However, because neither "a" > 1 nor "a" < 1, this only works for elements of the same type.

function intersect_arrays(a, b) {
    var sorted_a = a.concat().sort();
    var sorted_b = b.concat().sort();
    var common = [];
    var a_i = 0;
    var b_i = 0;

    while (a_i < a.length
           && b_i < b.length)
    {
        if (sorted_a[a_i] === sorted_b[b_i]) {
            common.push(sorted_a[a_i]);
            a_i++;
            b_i++;
        }
        else if(sorted_a[a_i] < sorted_b[b_i]) {
            a_i++;
        }
        else {
            b_i++;
        }
    }
    return common;
}

Example:

var array1 = ["cat", "sum", "fun", "hut"], //modified for additional match
    array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];
intersect_arrays(array1, array2);
>> ["cat", "hut"]
Community
  • 1
  • 1
phant0m
  • 16,595
  • 5
  • 50
  • 82
  • The complexity is actually O(nlogn + mlogm + n + m), you forgot to consider the while loop while calculating. – Partha Apr 27 '16 at 19:25
  • @Partha `n` is subsumed by the faster growing `n logn`, the same applies for `m` and `m log n`. – phant0m Apr 28 '16 at 12:13
12

Loop through the second array each time you iterate over an element in the first array, then check for matches.

var array1 = ["cat", "sum", "fun", "run"],
    array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];

function getMatch(a, b) {
    var matches = [];

    for ( var i = 0; i < a.length; i++ ) {
        for ( var e = 0; e < b.length; e++ ) {
            if ( a[i] === b[e] ) matches.push( a[i] );
        }
    }
    return matches;
}

getMatch(array1, array2); // ["cat"]
David G
  • 94,763
  • 41
  • 167
  • 253
  • this uses the **length of array 1 * the length of array 2** amount of loops... 24 loops in this case. – jeremy Sep 15 '12 at 01:03
  • 1
    no problem. it works, but its just extremely unnecessary and could potentially take forever to run. you can check out my answer for probably a better 1 loop solution – jeremy Sep 15 '12 at 01:12
12
var array1  = [1, 2, 3, 4, 5, 6];
var array2 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var array3 = array2.filter(function(obj) { 
    return array1.indexOf(obj) !== -1; 
});
Jesse Reza Khorasanee
  • 3,140
  • 4
  • 36
  • 53
hardik beladiya
  • 268
  • 2
  • 12
10

You can use javascript function .find() As it says in MDN, it will return the first value that is true. If such an element is found, find immediately returns the value of that element. Otherwise, find returns undefined.

var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];

found = array1.find((val, index) => {
  console.log('index', index) // Stops at 0
  return array2.includes(val)
})
console.log(found)

Or use .filter(), which loops through every elements first, then give back the result to you.

var array1 = ["cat", "sum", "fun", "run", "cat"];
var array2 = ["bat", "cat", "dog", "sun", "hut", "gut"];

found = array1.filter((val, index) => {
  console.log('index', index) // Stops at array1.length - 1
  return array2.includes(val)
})
console.log(found)
Irfandy Jip
  • 1,308
  • 1
  • 18
  • 36
4

use lodash

GLOBAL.utils = require('lodash')
var arr1 = ['first' , 'second'];
var arr2 = ['second '];

var result = utils.difference(arr1 , arr2);
console.log ( "result :" + result );
ssuperczynski
  • 3,190
  • 3
  • 44
  • 61
Hanu
  • 119
  • 9
3

Libraries like underscore and lodash have a utility method called intersection to find matches in arrays passed in. Take a look at: http://underscorejs.org/#intersection

leojh
  • 7,160
  • 5
  • 28
  • 31
2

Done as a answer so I can do formatting...

This is the the process you need to go through. Looping through an array for the specifics.

create an empty array
loop through array1, element by element. {
  loop through array2, element by element {
    if array1.element == array2.element {
      add to your new array
    }
  }
}
Jeremy J Starcher
  • 23,369
  • 6
  • 54
  • 74
  • this uses the **length of array 1 * the length of array 2** amount of loops... 24 loops in this case.. it'd be better to just check if the index of the value in array1 is existent in array2 and then only 1 loop would be used. see my answer. – jeremy Sep 15 '12 at 01:07
  • I thought about that. `.indexOf()` still isn't supported everywhere, though it can be monkeypatched in easily enough... and `.indexOf()`, at least in the Mozilla monkeypatch version (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf) still loops. It just moves one of the loops to the `indexOf` function instead. – Jeremy J Starcher Sep 15 '12 at 01:14
  • It's supported in all the major browsers, look at the compatibility table... – jeremy Sep 15 '12 at 01:16
  • I'm well aware of where `indexOf` is, and is not, supported. My _primary_ point is that your solution is still a two-loop solution. One of the loops is just hidden. – Jeremy J Starcher Sep 15 '12 at 01:20
  • it's much faster than actually using a hard coded loop though. – jeremy Sep 15 '12 at 01:22
  • 1
    True -- but I doubt execution speed is the desired goal here. This is a "Level 101" question, so the OP needs an answer that best describes the entire process without shortcuts. Understanding _exactly_ what is going on is more important. – Jeremy J Starcher Sep 15 '12 at 01:25
2

If your values are non-null strings or numbers, you can use an object as a dictionary:

var map = {}, result = [], i;
for (i = 0; i < array1.length; ++i) {
    map[array1[i]] = 1;
}

for (i = 0; i < array2.length; ++i) {
    if (map[array2[i]] === 1) {
        result.push(array2[i]);

        // avoid returning a value twice if it appears twice in array 2
        map[array2[i]] = 0;
    }
}

return result;
ChaseMedallion
  • 20,860
  • 17
  • 88
  • 152
2

With some ES6:

let sortedArray = [];
firstArr.map((first) => {
  sortedArray[defaultArray.findIndex(def => def === first)] = first;
});
sortedArray = sortedArray.filter(v => v);

This snippet also sorts the firstArr based on the order of the defaultArray

like:

let firstArr = ['apple', 'kiwi', 'banana'];
let defaultArray = ['kiwi', 'apple', 'pear'];
...
console.log(sortedArray);
// ['kiwi', 'apple'];
ddobby94
  • 273
  • 4
  • 12
0

Iterate on array1 and find the indexof element present in array2.

var array1 = ["cat", "sum","fun", "run"];
var array2 = ["bat", "cat","sun", "hut", "gut"];
var str='';
for(var i=0;i<array1.length;i++){
        if(array2.indexOf(array1[i]) != -1){
           str+=array1[i]+' ';
       };
    }
console.log(str)
jsduniya
  • 2,464
  • 7
  • 30
  • 45