-1

I'm trying to delete all matched items from an array but it leaves Always one item in it.

var item1 = {item: "item1"},
    array = [{
        item: "item1"},{
        item: "item_non"},{
        item: "item1"},{
        item: "item_non"},{
        item: "item1"},{
        item: "item1"},{
        item: "item1"},{
        item: "item_non"},{
        item: "item_non"
    }];
array.forEach(function(items){
    if(item1.item === items.item){
        var index = array.indexOf(items);
        if(index !== -1){
            array.splice(index,1);
        }
    }
});

I also fiddle it, it deletes only 4/5 items that matches instead of 5/5.

Fiddle

There is no option to use Array#filter I need to delete the objects.

3
  • 5
    Modifying the array while iterating via .forEach() is the fundamental problem. The right way to do this is with .filter() or with a simple for loop. If you think you can't use .filter(), you should explain why. Commented Oct 21, 2015 at 23:04
  • When you remove an item, you change following indexes. You can fix it by iterating backwards. Commented Oct 21, 2015 at 23:05
  • Related: stackoverflow.com/questions/25994909/… Commented Oct 21, 2015 at 23:19

3 Answers 3

6

The problem is that .splice() moves all the elements after the deleted element down. So if you delete element 3, element 4 becomes 3, 5, becomes 4, and so on. The next iteration of the loop will process element 4, but that's the original element 5 -- the original element 4 is skipped.

The way to solve this is to process the array in reverse. .forEach can't do this, AFAIK, so you have to use a for loop:

for (var i = array.length - 1; i >= 0; i--) {
    item = array[i];
    if (item1.item == item.item) {
        array.splice(i, 1);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

I hope the guy asking the question realizes this is the right answer for what he is asking..
0

Here's another version that does in-place manipulation of the array.

http://codepen.io/anon/pen/XmZrww?editors=001

// remove the matching item and return the array
var filterArray = function (arr, obj) {
  for (var i = 0, len = arr.length; i < len; i++) {
    if (arr[i].item === obj.item) {
      arr.splice(i, 1);
      len--;
      i--;
    }
  }
  return arr;
};

var item1 = {item: "item1"};
var data = [
  {item: "item1"},
  {item: "item_non"},
  {item: "item1"},
  {item: "item_non"},
  {item: "item1"},
  {item: "item1"},
  {item: "item1"},
  {item: "item_non"},
  {item: "item_non"}
];

console.log(filterArray(data, item1));

3 Comments

You're initializing i to 0, and then doing i--. So it will then try to test arr[-1], which doesn't exist.
Oh, I see. You decrement i inside the loop, then the for() increments it back.
Yeah but your answer is the more succinct way to do this. Upvoted
-1

Here's my version http://codepen.io/anon/pen/VvQZVe?editors=001

Note I cleaned up the code a bit.

Repeatedly using indexOf in a loop is expensive. The worst case for doing that in a big array is having to go to almost the end of the loop many times.

This version potentially uses almost 2x the memory (imagine a big array where there's only a single item to be removed). But, its faster.

// indexOf is expensive, especially in a loop.
// here we just iterate straight through the array and append
// mismatching properties to another array that gets returned.
var filterArray = function (arr, obj) {
  var returnArray = [];

  arr.forEach(function (el) {
    if (el.item !== obj.item) {
      returnArray.push(el);
    }
  });

  return returnArray;
};

var item1 = {item: "item1"};
var data = [
  {item: "item1"},
  {item: "item_non"},
  {item: "item1"},
  {item: "item_non"},
  {item: "item1"},
  {item: "item1"},
  {item: "item1"},
  {item: "item_non"},
  {item: "item_non"}
];

console.log(filterArray(data, item1));

3 Comments

Your filterArray function is equivalent to Array.prototype.filter, which he said won't work for him.
He said he can't use Array.filter. He doesn't say anything about not being able to use a function that does something like a polyfill.
He said "I need to delete the objects". I think that means that he needs to keep the same array, not create a new array like filter does.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.