Javascript algorithm to find elements in array that are not in another array

JavascriptJqueryAlgorithmArrays

Javascript Problem Overview


I'm looking for a good algorithm to get all the elements in one array that are not elements in another array. So given these arrays:

var x = ["a","b","c","t"];
var ​​​​​​​​​y = [​​​​​​​"d","a","t","e","g"];

I want to end up with this array:

var z = ["d","e","g"];

I'm using jquery, so I can take advantage of $.each() and $.inArray(). Here's the solution I've come up with, but it seems like there should be a better way.

// goal is to get rid of values in y if they exist in x
var x = ["a","b","c","t"];
var y = ["d","a","t","e","g"];
  
var z = [];
$.each(y, function(idx, value){
  if ($.inArray(value,x) == -1) {
    z.push(value);
  }
});
​alert(z);  // should be ["d","e","g"]

Here is the code in action. Any ideas?

Javascript Solutions


Solution 1 - Javascript

in ES6 simply

const a1 = ["a", "b", "c", "t"];
const a2 = ["d", "a", "t", "e", "g"];

console.log( a2.filter(x => !a1.includes(x)) );

(another option is a2.filter(x => a1.indexOf(x)===-1) )

Solution 2 - Javascript

Late answer with the new ECMA5 javascript:

var x = ["a","b","c","t"];
var y = ["d","a","t","e","g"];

myArray = y.filter( function( el ) {
  return x.indexOf( el ) < 0;
});

Solution 3 - Javascript

var z = $.grep(y, function(el){return $.inArray(el, x) == -1}); 

Also, that method name is too short for its own good. I would expect it to mean isElementInArray, not indexOf.

For a demo with objects, see http://jsfiddle.net/xBDz3/6/

Solution 4 - Javascript

Here's an alternative using underscore.js:

function inAButNotInB(A, B) {
  return _.filter(A, function (a) {
    return !_.contains(B, a);
  });
}

Solution 5 - Javascript

I am quite late now but maybe it will be helpful for someone.

If the array is not just a simple array but an array of objects then the following can be used:

var arr1 = [
    {
      "prop1": "value1",
      "prop2": "value2",
    },
    {
      "prop1": "value3",
      "prop2": "value4",
    },
    {
      "prop1": "value5",
      "prop2": "value6",
    },
  ];

var arr2 = ['value1','value3', 'newValue'];

// finds all the elements of arr2 that are not in arr1
arr2.filter( 
    val => !arr1.find( arr1Obj => arr1Obj.prop1 === val)
); // outputs "newValue"

Solution 6 - Javascript

This is a late answer, but it uses no libraries so some may find it helpful.

/**
 * Returns a non-destructive Array of elements that are not found in
 * any of the parameter arrays.
 *
 * @param {...Array} var_args   Arrays to compare.
 */
Array.prototype.uniqueFrom = function() {
  if (!arguments.length)
    return [];
  var a1 = this.slice(0); // Start with a copy

  for (var n=0; n < arguments.length; n++) {
    var a2 = arguments[n];
    if (!(a2 instanceof Array))
      throw new TypeError( 'argument ['+n+'] must be Array' );

    for(var i=0; i<a2.length; i++) {
      var index = a1.indexOf(a2[i]);
      if (index > -1) {
        a1.splice(index, 1);
      } 
    }
  }
  return a1;
}

Example:

var sheetUsers = ['[email protected]','[email protected]','[email protected]'];
var siteViewers = ['[email protected]','[email protected]','[email protected]'];
var viewersToAdd = sheetUsers.uniqueFrom(siteViewers);  // [[email protected]]
var viewersToRemove = siteViewers.uniqueFrom(sheetUsers);  // [[email protected]]

Solution 7 - Javascript

 findDiff = (A, B) => {
     return  A.filter(function (a) {
          return !B.includes(a);
     });
 }

Solution 8 - Javascript

Make sorted copies of the arrays first. If the top elements are equal, remove them both. Otherwise remove the element that is less and add it to your result array. If one array is empty, then add the rest of the other array to the result and finish. You can iterate through the sorted arrays instead of removing elements.

// assume x and y are sorted
xi = 0; yi = 0; xc = x.length; yc = y.length;
while ( xi < xc && yi < yc ) {
  if ( x[xi] == y[yi] ) {
    xi += 1;
    yi += 1;
  } else if ( x[xi] < y[yi] ) {
    z.push( x[xi] );
    xi += 1;
  } else {
    z.push( y[yi] );
    yi += 1;
  }
}
// add remainder of x and y to z.  one or both will be empty.

Solution 9 - Javascript

Maybe jLinq can help you?

It lets you run queries like this against javascript objects.

For example:

var users = [ { name: "jacob", age: 25 },  { name: "bob" , age: 30 }]
var additionalusers = [ { name: "jacob", age: 25 },  { name: "bill" , age: 25 }]

var newusers = jLinq.from(users).except(additionalusers).select();

>>> newusers = [ { name: "bob" , age: 30 } ]

It's a bit overkill for you at the moment, but it's a robust solution that I was glad to learn about.

It can do intersects, unions, handle boolean logic and all kinds of great linq style goodness.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTaurenView Question on Stackoverflow
Solution 1 - JavascriptkofifusView Answer on Stackoverflow
Solution 2 - JavascriptMaurizio In denmarkView Answer on Stackoverflow
Solution 3 - JavascriptMatthew FlaschenView Answer on Stackoverflow
Solution 4 - JavascriptMatt WoelkView Answer on Stackoverflow
Solution 5 - JavascriptAhmerMHView Answer on Stackoverflow
Solution 6 - JavascriptMogsdadView Answer on Stackoverflow
Solution 7 - JavascriptYoav SchniedermanView Answer on Stackoverflow
Solution 8 - JavascriptdrawnonwardView Answer on Stackoverflow
Solution 9 - JavascriptKoobzView Answer on Stackoverflow