vinz
vinz

Reputation: 348

Splice multiple arrays in multidimensional array javascript

I have an multidimensional array

[{id:0, type:1}, {id:1, type:1}, {id:2, type:2}]

What I aim to do is to remove all type 1 and so the desired result should leave id:2, type:2

tmpType = 1;
for (var i in arr) {
    if(arr[i].type == tmpType) {
        arr.splice(i, 1);
    }
}

However in the loop, from what I understand it will loop thrice but everytime I splice, the loop differs. This is the result I am getting.

{{id:1, type:1}, {id:2, type:2}}

If i have 3 kinds of type:1, I will always have the last one still in the array.

Upvotes: 2

Views: 14061

Answers (5)

Paul S.
Paul S.

Reputation: 66304

As splice changes the length you either need to move your iterator or iterate downwards.

You should also be using for, not for..in to iterate over an Array

var arr = [{id:0, type:1}, {id:1, type:1}, {id:2, type:2}];

var type = 1,
    i;                                  // OR    // i = arr.length;
for (i = arr.length - 1; i >= 0; --i) {          // while (i-- > 0) {
    if (arr[i].type == type) {
        arr.splice(i, 1);
    }
}

arr; // [{"id": 2, "type": 2}]

Other answers suggest using a the filter method of Arrays which is a great alternative option and you may find it cleaner. However, please be aware the result of these two ways are slightly different as this way will modify the original Array reference ("has side effects"), whereas the filter method will create an entirely new instance of Array and leave the original untouched.


You can think of filter like this, which also shows why it's a bit expensive

function filter(arr, test) {
    var i,
        arr_out = [];
    for (i = 0; i < arr.length; ++i)
        if (i in arr && test(arr[i]) // invoking test each time is expensive
            arr_out.push(arr[i]);
    return arr_out;
}

splice can be expensive too, however, as you are moving all the indicies around.

The least expensive way to do this without side effects (i.e. original left alone) is to do a mix of the two; a manual for loop which pushes to a new Array with out test written into it, not invoked seperately

// arr as before
var arr2 = [],
    i;
for (i = 0; i < arr.length; ++i)
    if (arr[i].type === type) // doing our test directly, much cheaper
        arr2.push(arr[i]);
arr2; // desired array

For a original modified, easiest option is to use the splice method I wrote at the start of this answer.
The other option is to copy the original, var arr2 = arr.slice(), then empty the original, arr.length = 0;, then do the last loop I showed except with arr and arr2 swapped around to re-populate arr

Upvotes: 3

Luke
Luke

Reputation: 5708

Assuming you really meant:

[{id:0, type:1}, {id:1, type:1}, {id:2, type:2}]

You can use filter:

var oldArr = [{id:0, type:1}, {id:1, type:1}, {id:2, type:2}];
var newArr = oldArr.filter(function(obj) {
  return obj.type !== 1; 
});

Upvotes: 1

kpimov
kpimov

Reputation: 13922

You should loop backwards through the array. Using splice looping forwards will mean that you'll skip past the element after the one you splice on each iteration, now that it has the same index as the one you removed.

var arr = [{id: 0, type: 1}, {id: 1, type: 1}, {id: 2, type: 2}];
for (var i = arr.length; i--;) {
        if (arr[i].type === 1) arr.splice(i, 1);
}

You could also do this:

var arr = [{id: 0, type: 1}, {id: 1, type: 1}, {id: 2, type: 2}];
arr = arr.filter(function (obj) {
        return obj.type !== 1;
});

Upvotes: 1

jmar777
jmar777

Reputation: 39649

You should probably just use .filter() for this:

var arr = [{id:0, type:1}, {id:1, type:1}, {id:2, type:2}];

var filtered = arr.filter(function(item) {
    return item.type !== 1;
});

Demo: http://jsbin.com/tafuhasoti/edit?js,console

Upvotes: 3

Hath995
Hath995

Reputation: 1300

Assuming you have an actual array.

var data = [{id:0, type:1}, {id:1, type:1}, {id:2, type:2}]
//Array has a method filter
var filterdata = data.filter(function(element, index, array){
  return element.type == 2;
})
//filterdata will contain an array of only objects that have type 2

Upvotes: 1

Related Questions