I Love Stackoverflow
I Love Stackoverflow

Reputation: 6868

Find item in another array and remove matched item from array

I have two array with records like below:

var cars = ["Saab", "Volvo", "BMW"]; 

var cars1 = ["Saab", "Volvo", "BMW"]; 

Now I want to remove matching element from Cars1 so at the end my Cars1 array will be like below :

var cars = ["Saab", "Volvo", "BMW"]; 

var cars1 = ["Saab", "Volvo", "BMW"]; 

 for (var i = 0; i < cars1.length; i++) {
                for (var j = 0; j < cars.length; j++) {
                    if (cars1[i] == cars[j]) {
                        cars1.splice(i, 1);
                        break;
                    }
                }
            }
console.log(cars1)

Expected Output :

 var cars1 = []; 

I am not getting expected output.

Upvotes: 0

Views: 121

Answers (5)

Matthias Danetzky
Matthias Danetzky

Reputation: 682

After the first call to cars1.splice(i, 1), the cars1 has one less element, hence it doesn't make much sense to continue with the outer loop. To make the code cleaner I`d suggest to use indexOf instead of the inner loop.

var cars = ["Saab", "Volvo", "BMW"];
var cars1 = ["Saab", "Volvo", "BMW"];

for (var i = 0; i < cars.length; i++) {
  var carPositionInCars1 = cars1.indexOf(cars[i]);
  if (carPositionInCars1 != -1) {
    cars1.splice(carPositionInCars1, 1);
  }
}
console.log(cars1);

Upvotes: 0

Denys S&#233;guret
Denys S&#233;guret

Reputation: 382102

You're missing some items because the deleted item is replaced with the next one when you iterate. Just loop the other way, with i decreasing:

var cars = ["Saab", "Volvo", "BMW"]; 

var cars1 = ["Saab", "Volvo", "BMW"]; 

 for (var i=cars1.length; i--;) {
                for (var j = 0; j < cars.length; j++) {
                    if (cars1[i] == cars[j]) {
                        cars1.splice(i, 1);
                        break;
                    }
                }
            }
console.log(cars1)

Note that you don't really need an explicit double loop. One of the possible alternatives would be to use indexOf. Another one (more efficient in case of big arrays) would be to put the content of cars1 into an instance of Set. And if you don't need to keep the same array, there's also filter of course.

Here's how it would be with a set and reduce (a very efficient solution when cars arrays are big):

var cars = ["Saab", "Volvo", "BMW"]; 
var cars1 = ["Saab", "Volvo", "BMW"];
 
var set = cars.reduce((s,c) => s.add(c), new Set);
cars1 = cars1.filter(c => !set.has(c)); 
console.log(cars1);

And for antique browsers:

var cars = ["Saab", "Volvo", "BMW"]; 
var cars1 = ["Saab", "Volvo", "BMW"];
 
var set = cars.reduce(function(s,c){
     s[c] = true;
     return s;
}, Object.create(null));
cars1 = cars1.filter(function(c){
     return !set[c];
}); 
console.log(cars1);

Upvotes: 2

Joschua Schneider
Joschua Schneider

Reputation: 4093

Using a simple functional approach to save some space and make it cleaner I would recommend using Array.prototype.filter in combination with Array.prototype.indexOf like this:

var cars = ["Saab", "Volvo", "BMW"]; 

var cars1 = ["Saab", "Volvo", "BMW", "VW"];

cars1 = cars1.filter(car => cars.indexOf(car) < 0)

console.log(cars1)

The filter method calls the passed callback for each element, if the callback returns false the element won't be returned if returned true the element gets returned. Notice that the filter method returns a new array, and does not modify the current one! Thanks to @denys-séguret for mentioning it!

indexOf returns the index of the passed element. If not found -1 is returned. Thats why whe filter all elements out, where the index is < 0, only returning elements that are not already in the cars array.

Upvotes: 3

kind user
kind user

Reputation: 41893

You are getting wrong result, because with every slice(), elements inside are changing their index. So after the first loop, Volvo will get 0 index and actually item with 0 index was already processed, so the function won't operate it. That's why it stays inside after function.

I suggest you to use Array#filter.

var cars = ["Saab", "Volvo", "BMW"],
    cars1 = ["Saab", "Volvo", "BMW"]; 
    
    var result = cars.filter(v => cars1.indexOf(v) == -1);
    console.log(result);

Upvotes: 1

Kamil Latosinski
Kamil Latosinski

Reputation: 846

The thing you are trying to do is called difference. The opposite is intersection.

var cars = ["Saab", "Volvo", "BMW", "Skoda"]; 

var cars1 = ["Saab", "Volvo", "BMW"]; 

function diff(arr1, arr2) {
  return arr1.filter(x => arr2.indexOf(x) === -1)
}

function intersec(arr1, arr2) {
  return arr1.filter(x => arr2.indexOf(x) > -1)
}

console.log(
  diff(cars, cars1),
  intersec(cars, cars1)
);

Upvotes: 1

Related Questions