Mustang
Mustang

Reputation: 604

Splice() does not make the array empty

I have arrays x,y and z. While iterating through x, based on a condition I need to keep removing the elements from z. Here's what I am trying to do:

var x = ["test0", "test1", "test2"];
var y = ["test0", "test1", "test2"];
var z = ["test0", "test1", "test2"];

function myFunction(){
    for (var i=0; i<x.length; i++){
        for (var j=0; j<y.length; j++){
            if(x[i] == y[j]){
                z.splice(i,1);
            }
        }

    }
document.getElementById("demo").innerHTML = z;
}

At the end of iteration, z should get empty. But it is always showing me 'test1' element remaining. Since the correct index is not getting spliced I tried to do z.splice(i--,1) but that did not work either.

Please advise what is the best way to resolve this ?

Upvotes: 2

Views: 1708

Answers (4)

RobG
RobG

Reputation: 147553

As answers have said, your problem is that splicing z means the indexes and values are no longer aligned between the arrays. A common alternative to keeping track of removed indexes when removing elements from any kind of list is to iterate from the end to the start, e.g.

var x = ["test0", "test1", "test2"];
var y = ["test0", "test1", "test2"];
var z = ["test0", "test1", "test2"];

function myFunction(){
    for (var i=x.length; i>0; ){
        for (var j=y.length; j> 0; ){
            if(x[--i] == y[--j]){
                z.splice(i,1);
            }
        }
    }
    document.write('"' + z.join() + '"');
}

myFunction();

And if you use some of the syntactic sugar introduced with ES5, reduceRight helps to reduce the amount of code:

function myFunction(){
  x.reduceRight(function(n, x, i) {
    y.reduceRight(function(n, y) {
      if (x == y) z.splice(i, 1)
    }, null);
  }, null)
  document.write('"' + z.join() + '"');
}

Upvotes: 3

Ori Drori
Ori Drori

Reputation: 193358

It's quite easy to understand, if you create some sort of a table. The problem is that after the first splice, the index of z is not like the indexes of x and y:

x[0] = j[0] : i = 0 -> z.splice(0, 1); - test0 is removed - z = ["test1", "test2"];
x[1] = j[1] : i = 1 -> z.splice(1, 1); - test2 is removed - z = ["test1"];
x[2] = j[2] : i = 2 -> z.splice(2, 1); - nothing is removed - z = ["test1"];

Solution:

function myFunction() {
    var removed = 0; // removed items counter
    for (var i = 0; i < x.length; i++) {
        for (var j = 0; j < y.length; j++) {
            if (x[i] == y[j]) {
                z.splice(i - removed, 1); // subtract removed counter from index
                removed++; // increment removed counter
            }
        }

    }
}

Upvotes: 3

charlietfl
charlietfl

Reputation: 171698

Instead of keeping track of the moving indices, you can find the current index using indexOf()

for (var i=0; i<x.length; i++){
    for (var j=0; j<y.length; j++){
        if(x[i] == y[j]){
            z.splice( z.indexOf(x[i]) , 1 );
        }
    }
}

Upvotes: 0

Paul
Paul

Reputation: 141935

You could resolve it by keeping track of the number of removed elements from z:

var numRemoved = 0;
for (var i=0; i<x.length; i++){
    for (var j=0; j<y.length; j++){
        if(x[i] == y[j]){
            z.splice( i - numRemoved++ , 1 );
        }
    }
}

Upvotes: 1

Related Questions