0

I have two arrays and want to remove from one all elements which exist in the other as well.

  • Can this be done with native JS?
  • Is there a jQuery function to do it?
  • What are best practices to do so (the faster the better)

p.s.: just post code in other languages too, maybe I can port it to Javascript

Update, after accepting answer to help the JS dudes ;-)

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
    var rest = this.slice((to || from) + 1 || this.length);
    this.length = from < 0 ? this.length + from : from;
    return this.push.apply(this, rest);
};
// Array Contains - By Helmuth Lammer (TU Vienna)
Array.prototype.contains = function(key){

    for(var i = 0; i<this.length; i++){
        if(this[i]  == key) return i;
    }

    return false;
}

(There is a native JS method named contains too, but it should work)

5
  • replace to what? you want to merge them? Commented Jul 6, 2010 at 17:10
  • @galam He wants to make A and B disjoint, leaving A unchanged. Commented Jul 6, 2010 at 17:13
  • sorry my fault *displace Commented Jul 6, 2010 at 17:17
  • 1
    now I really don't know what you mean. Do you mean "remove" so that the items in A don't appear in B as @glowcoder suggests? Commented Jul 6, 2010 at 17:21
  • damn my english is too bad. remove is the right thing. sorry for that. trying out @glowcoders solution in some minutes ... Commented Jul 6, 2010 at 17:30

4 Answers 4

1

Given two sets a and b, to remove all elements present in a from b. Translation to array formatting and javascript left as an exercise to the reader. Optimizations exist for sorted arrays.

for(element e : b) {
    if(a.contains(e)) {
         b.remove(e);
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

well works not in JS with this syntax, but the idea is clear. i think it is not very fast. the contains() and the remove() methode have to run through all items each time ... or am i absolutely wrong?
The idea was to take the pseudocode and apply to any language. The contains is necessary, and is O(n). The remove can be optimized by using a secondary structure (ArrayList-esque comes to mind) to build a new B array, and adding elements to it, rather than removing. Not being a Javascript guy, I don't know what mechanisms exist for such operations.
1
var foo = [1, 2, 3, 4, 5];

function removeAll(a, b) {
    var i = 0,
        j;

    while (i < b.length) {
        for (j = 0; j < a.length; j++) {
            if (a[j] === b[i]) {
                b.splice(i, 1);
                i--;
                break;
            }
        }
        i++;
    }
}

removeAll([2, 4], foo);
// foo === [1, 3, 5]

Comments

0

[See it in action]

// two arrays
var arr1 = [1,2,3,4,5];
var arr2 = [4,5,6,7,8];

// returns the element's index in an array
// or -1 if there isn't such an element
function indexOf( arr, el ) {
  for ( var i = arr.length; i--; ) {
    if ( arr[i] === el ) return i;
  }
  return -1;
}

// go through array1 and remove all
// elements which is also in array2
​for ( var i = arr1.length; i--; )​ {
  if ( indexOf( arr2, arr1[i] ) !== -1 ) {
    arr1.splice(i, 1);
  }
}

// result should be: arr1 = [1,2,3] 
alert( arr1 );
​

Comments

0

I had to write a code once where an Ajax call would return an array containing a list of element which must be deleted from a local (client-side) array.

I ended implementing it this way:

// The filter method creates a new array with all elements that pass the
// test implemented by the provided function.
local_array = local_array.filter( function (element) {
    // Now I check if this element is present in the "delete" array. In order to do 
    // that I use the "some" method which runs a callback function for each of the
    // array elements and returns true or false.
    return !items_to_delete.some( function(item) {
        return item.pk === element.pk;
    });
});

Edit: In order to make it cross-browser (I am talking about IE here). You will have to define the some and filter functions. Just put this somewhere in your code:

if (!Array.prototype.some)
{
  Array.prototype.some = function(fun /*, thisp*/)
  {
    var i = 0,
        len = this.length >>> 0;

    if (typeof fun != "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (; i < len; i++)
    {
      if (i in this &&
          fun.call(thisp, this[i], i, this))
        return true;
    }

    return false;
  };
}

if (!Array.prototype.filter)
{
  Array.prototype.filter = function(fun /*, thisp*/)
  {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    var res = [];
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this)
      {
        var val = this[i]; // in case fun mutates this
        if (fun.call(thisp, val, i, this))
          res.push(val);
      }
    }

    return res;
  };
}

2 Comments

nice but not unfortunately cross-browser :(
it's cross-browser. but you will have to define the some and filter methods if the client is using IE

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.