2

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.

2
  • 2
    Your first literal is invalid syntax Commented Jul 27, 2015 at 18:11
  • 1
    I think you meant to do [{id:0, type:1}, {id:1, type:1}, {id:2, type:2}] instead of {{id:0, type:1}, {id:1, type:1}, {id:2, type:2}} Commented Jul 27, 2015 at 18:13

5 Answers 5

3

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

Sign up to request clarification or add additional context in comments.

5 Comments

this is what i want but couldn't write it out. didn't know about the filter method, is there efficiency difference between yours and filter? I would need the original to be touched so would be going for this method. thanks heaps.
Unless you're dealing with arrays with 10,000+ items, you will never, ever, ever, ever notice a performance difference.
@jmar777 please see the spec, es5.github.io/#x15.4.4.20 part 9.b. . It is true that the efficiency optimisation will not be noticeable unless you're doing some really heavy work though
@PaulS. I would confess to being a massive arse, but I'm too busy eating crow at the moment. Thanks for the correction...
@PaulS. Also, even if I had been right, my (removed) reply was just childish. Please accept my apology. :\
3

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

Comments

1

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 

Comments

1

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; }); 

Comments

1

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; }); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.