views:

79

answers:

3

What I am trying to do is if I have Array a = {1,2,3,4}; b = {1,2};

Then I want subset array as c = {3,4};

Can anybody help me?

+2  A: 

I'm not aware of any built-in way to do this, you basically have to loop through c and check whether each element is in a and, if so, remove it. The Array#indexOf method can help you with checking, but not all implementations have it (though most do). Removal can be via Array#splice.

So:

var a, c, index;
a = [1, 2];
c = [1, 2, 3, 4];
for (index = c.length - 1; index >= 0; --index) {
    if (a.indexOf(c[index]) >= 0) {
        c.splice(index, 1);
    }
}

...and then either supply your own implementation of Array#indexOf if your environment doesn't support it, or use a library like Prototype that supplies it for you (jQuery gives it to you as well, but through its own jQuery.inArray function). If doing it yourself:

if (!Array.prototype.indexOf) {
  (function() {
    Array.prototype.indexOf = Array_indexOf;
    function Array_indexOf(elm) {
      var index;
      for (index = 0; index < this.length; ++index) {
        if (this[index] === elm) {
          return index;
        }
      }
      return -1;
    }
  })();
}

Note that adding to the Array prototype as above can be dangerous when done with poorly-written code code that makes assumptions about the environment. Specifically, code that treats for..in as though it loops through array element indexes (it doesn't, it looks through object property names) will get messed up if you add to the Array prototype. (That's probably why jQuery doesn't do it.)

Live example

T.J. Crowder
Why did you put the definition of indexOf in a closure instead of like: if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(elm) {...};}; ?
thomasmalt
@thomasmalt: Because I like functions to have names, and unfortunately that's the only way that's compatible with IE (JScript) to give the function a name without creating a global symbol and without creating the function if we don't have to: http://blog.niftysnippets.org/2010/03/anonymouses-anonymous.html Your way is great other than the function not having a name.
T.J. Crowder
Thanks. I normally prefer to extend by assigning anonymous functions to variables. For me that enhances readability and makes it easy to create well formatted, well documented, source code. :)
thomasmalt
@thomasmalt: Fair enough. I like to have function names in my call stack when using a debugger. :-) Hopefully, someday, Microsoft will fix the JScript bug that prevents just using a named function expression like `Array.prototype.indexOf = function Array_indexOf() { ... }`. But sadly, not even JScript 6 (IE8) fixes it: http://jsbin.com/alexe3/2 Maybe IE9, they're doing a *lot* of standards work...
T.J. Crowder
And debugging is a really good reason to use named functions. Thanks for the tip.
thomasmalt
@Crowder Thanks your first code snippet works fine for me. I did small changes as per my requirement.
Kamlesh Bhure
@Kamlesh: Good deal, glad that helped.
T.J. Crowder
+1  A: 

Assuming that you're after the relative complement of b in a.

function complement(a, b) {
  var c = new Array();

  // convert A to an associative array
  var myHash = new Array();
  for (var i = 0; i < a.length; ++i) {
    myHash[a[i]] = 1;
  }

  // remove the elements that exist in B
  for (var i = 0; i < b.length; ++i) {
    delete myHash[b[i]];
  }

  // what's left is A \ B
  // assumes that no-one broke Array by adding new properties to the prototype
  var i = 0;
  for (var n in myHash) {
    c[i++] = n;
  }
  return c;
}

// test
var a = [1, 2, 3, 4];
var b = [1, 2];
var c = complement(a, b);
alert(c);

This should scale well for larger arrays, since it uses hash table indexing rather than linear searches to remove the unwanted elements.

Alnitak
hash-based solutions don't work when (some of) array elements are Objects.
stereofrog
A: 
a = [1, 2, 3, 4]
b = [2, 1, 5]

comp = a.filter(function(e) { return b.indexOf(e) < 0 })

see Array.filter and Array.indexOf for more details and degradation options.

stereofrog