Reputation: 6868
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
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
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
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
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
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