0

Simple question, but i dont know how to solve it

I have several arrays, but i only want the values that all arrays have in common

Im using javascript.

BadKnees
  • 149
  • 1
  • 1
  • 6

4 Answers4

2

Try looking for the value in each of the arrays using indexOF.

I never knew IE didn't support indexOf, but here's a quick fix from this post.

Community
  • 1
  • 1
Joseph
  • 117,725
  • 30
  • 181
  • 234
2

Something like this should work:

function getCommonElements() {
   var common = [],
       i, j;

   if (arguments.length === 0)
      return common;

   outerLoop:
   for (i = 0; i < arguments[0].length; i++) {
      for (j = 1; j < arguments.length; j++)
         if (-1 === arguments[j].indexOf(arguments[0][i]))
             continue outerLoop;

      common.push(arguments[0][i]);
   }
   return common;
}

Call it with any number of arrays as arguments:

var commonEls = getCommonElements(arr1, arr2, arr3, etc);

In case it's not obvious, the idea is to loop through the array from the first argument and test each of its elements against the other arrays. As soon as a particular element is found to not be in any of the other arrays from the other arguments continue on with the next element. Otherwise add the current element to the output array, common.

If you need to support browsers (IE < 9) that don't support the Array.indexOf() method you can either include the shim shown at the MDN page or replace the .indexOf() test from my code with another loop.

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
0

I think this should work.

var arr1 = [1,2,3,4]
  , arr2 = [2,3,4,5]
  , arr3 = [3,4,5,6]
  , arrs = [arr1, arr2, arr3];

var all = arr1.concat(arr2.concat(arr3)).sort()
  , red1 = all.filter(
        function(val, i, arr) {
          return i === arr.lastIndexOf(val)-1;
        })
  , red2 = red1.filter(
        function(val, i, arr) {
           var shared = true;
           arrs.forEach(
               function(arr, i, src) {
                 if (arr.indexOf(val) === -1)
                   shared = false;
               })
           return shared;
        })
Florian Salihovic
  • 3,921
  • 2
  • 19
  • 26
  • Can't really follow this. But i think this is the right way. Concat all arrays and the values that occur as often as the amount of arrays are the values in common. – BadKnees May 31 '12 at 23:47
  • 2
    Cool example of how to obfuscate even simple javascript with minimal effort. – RobG Jun 01 '12 at 00:31
  • I agree @RobG. BadKnees even mentioned not being able to follow it, yet accepted it anyway. (My way may have been quotidian, but it ended up shorter _and_ (in my opinion) easier to follow.) – nnnnnn Jun 01 '12 at 03:29
  • @nnnnnn—"quotidian"? Had to look that one up. ;-) – RobG Jun 01 '12 at 06:48
  • Well, it was after midnight yesterday and i clearly was too over motivated. What does the example do? Concatenate the array to get a bulk of all values, which get sorted. The first filter will return an array for values, which current index (indexOf()) matches the last index. So you'll a set of unique values. The second filter takes the set of values and checks all arrays (using forEach) if it present in all of the, using the arrs Array, which holds references to all single Arrays containing the values. – Florian Salihovic Jun 01 '12 at 07:35
  • Maybe i was to speedy to accept this answer @nnnnnn, but your answer can become real heavy when having many large arrays. But the correct answer, and the best way to do this is as i said above: concat all arrays, count the number of occurances of each value and return the values that occur as often as the amount of arrays. – BadKnees Jun 01 '12 at 10:06
  • concat is easy, counting can be found here:http://stackoverflow.com/questions/5667888/counting-occurences-of-javascript-array-elements – BadKnees Jun 01 '12 at 10:11
  • Sorry @BadKnees and Florian, obviously whichever answer helps you the most is the one you should accept so I shouldn't whinge. Regarding processing large arrays, any use of `.filter()` involves iterating over the whole array behind the scenes with the added overhead of a function call for each element, and in this case a `.forEach()` within a `.filter()` also with function calls for each element and `.indexOf` and `.lastIndexOf` too... – nnnnnn Jun 01 '12 at 11:51
0

If you are only concerned with modern browsers that support reduce(), then use this solution:

Finding matches between multiple JavaScript Arrays

If you must support IE6, then use my solution below. Here's how I got this to work in IE6 using jQuery:

  // Find common values across all arrays in 'a',
  // where 'a' is an array of arrays [[arr1], [arr2], ...]
  Object.common = function(a) {
    var aCommon = [];
    for (var i=0,imax=a[0].length,nMatch,sVal; i<imax; i++) {
      nMatch = 0;
      sVal = a[0][i];
      for (var j=1,jmax=a.length; j<jmax; j++) {
        nMatch += ($.inArray(sVal, a[j])>-1) ? 1 : 0;
      }
      if (nMatch===a.length-1) aCommon.push(sVal);
    }
    return aCommon;
  }

Basically, you just loop through each value of the first array in 'a' to see if it exists in the other arrays. If it exists, you increment nMatch, and after scanning the other arrays you add the value to the aCommon array if nMatch equals the total number of the other arrays.

Using the sample data provided by Florian Salihovic, Object.common(arrs) would return [3, 4].

If you cannot use jQuery, then replace $.inArray() with the code provided by Mozilla:

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/IndexOf

Community
  • 1
  • 1
thdoan
  • 18,421
  • 1
  • 62
  • 57