remove objects from array by object property

Javascript

Javascript Problem Overview


var listToDelete = ['abc', 'efg'];

var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}] // all that should remain

How do I remove an object from the array by matching object property?

Only native JavaScript please.

I am having trouble using splice because length diminishes with each deletion. Using clone and splicing on orignal index still leaves you with the problem of diminishing length.

Javascript Solutions


Solution 1 - Javascript

I assume you used splice something like this?

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) !== -1) {
        arrayOfObjects.splice(i, 1);
    }
}

All you need to do to fix the bug is decrement i for the next time around, then (and looping backwards is also an option):

for (var i = 0; i < arrayOfObjects.length; i++) {
var obj = arrayOfObjects[i];



if (listToDelete.indexOf(obj.id) !== -1) {
    arrayOfObjects.splice(i, 1);
    <b>i--;</b>
}




}

}

To avoid linear-time deletions, you can write array elements you want to keep over the array:

var end = 0;

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) === -1) {
        arrayOfObjects[end++] = obj;
    }
}

arrayOfObjects.length = end;

and to avoid linear-time lookups in a modern runtime, you can use a hash set:

const setToDelete = new Set(listToDelete);
let end = 0;

for (let i = 0; i < arrayOfObjects.length; i++) {
    const obj = arrayOfObjects[i];

    if (setToDelete.has(obj.id)) {
        arrayOfObjects[end++] = obj;
    }
}

arrayOfObjects.length = end;

which can be wrapped up in a nice function:

const filterInPlace = (array, predicate) => {
    let end = 0;

    for (let i = 0; i < array.length; i++) {
        const obj = array[i];

        if (predicate(obj)) {
            array[end++] = obj;
        }
    }

    array.length = end;
};

const toDelete = new Set(['abc', 'efg']);

const arrayOfObjects = [{id: 'abc', name: 'oh'},
                        {id: 'efg', name: 'em'},
                        {id: 'hij', name: 'ge'}];

filterInPlace(arrayOfObjects, obj => !toDelete.has(obj.id));
console.log(arrayOfObjects);

If you don’t need to do it in place, that’s Array#filter:

const toDelete = new Set(['abc', 'efg']);
const newArray = arrayOfObjects.filter(obj => !toDelete.has(obj.id));

Solution 2 - Javascript

You can remove an item by one of its properties without using any 3rd party libs like this:

var removeIndex = array.map(item => item.id).indexOf("abc");

~removeIndex && array.splice(removeIndex, 1);

Solution 3 - Javascript

With lodash/underscore:

If you want to modify the existing array itself, then we have to use splice. Here is the little better/readable way using findWhere of underscore/lodash:

var items= [{id:'abc',name:'oh'}, // delete me
                  {id:'efg',name:'em'},
                  {id:'hij',name:'ge'}];

items.splice(_.indexOf(items, _.findWhere(items, { id : "abc"})), 1);

With ES5 or higher

(without lodash/underscore)

With ES5 onwards we have findIndex method on array, so its easier without lodash/underscore

items.splice(items.findIndex(function(i){
    return i.id === "abc";
}), 1);

(ES5 is supported in almost all morden browsers)

About findIndex, and its Browser compatibility

Solution 4 - Javascript

To delete an object by it's id in given array;

const hero = [{'id' : 1, 'name' : 'hero1'}, {'id': 2, 'name' : 'hero2'}];
//remove hero1
const updatedHero = hero.filter(item => item.id !== 1);

Solution 5 - Javascript

findIndex works for modern browsers:

var myArr = [{id:'a'},{id:'myid'},{id:'c'}];
var index = myArr.findIndex(function(o){
  return o.id === 'myid';
})
if (index !== -1) myArr.splice(index, 1);

Solution 6 - Javascript

Check this out using Set and ES5 filter.

  let result = arrayOfObjects.filter( el => (-1 == listToDelete.indexOf(el.id)) );
  console.log(result);

Here is JsFiddle: https://jsfiddle.net/jsq0a0p1/1/

Solution 7 - Javascript

If you just want to remove it from the existing array and not create a new one, try:

var items = [{Id: 1},{Id: 2},{Id: 3}];
items.splice(_.indexOf(items, _.find(items, function (item) { return item.Id === 2; })), 1);

Solution 8 - Javascript

Loop in reverse by decrementing i to avoid the problem:

for (var i = arrayOfObjects.length - 1; i >= 0; i--) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) !== -1) {
        arrayOfObjects.splice(i, 1);
    }
}

Or use filter:

var newArray = arrayOfObjects.filter(function(obj) {
    return listToDelete.indexOf(obj.id) === -1;
});

Solution 9 - Javascript

> Only native JavaScript please.

As an alternative, more "functional" solution, working on ECMAScript 5, you could use:

var listToDelete = ['abc', 'efg'];
var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}]; // all that should remain

arrayOfObjects.reduceRight(function(acc, obj, idx) {
    if (listToDelete.indexOf(obj.id) > -1)
        arrayOfObjects.splice(idx,1);
}, 0); // initial value set to avoid issues with the first item and
       // when the array is empty.

console.log(arrayOfObjects);
[ { id: 'hij', name: 'ge' } ]

According to the definition of 'Array.prototype.reduceRight' in ECMA-262:

> reduceRight does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.

So this is a valid usage of reduceRight.

Solution 10 - Javascript

var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}] // all that should remain

as per your answer will be like this. when you click some particular object send the index in the param for the delete me function. This simple code will work like charm.

function deleteme(i){
    if (i > -1) {
      arrayOfObjects.splice(i, 1);
    }
}

Solution 11 - Javascript

If you like short and self descriptive parameters or if you don't want to use splice and go with a straight forward filter or if you are simply a SQL person like me:

function removeFromArrayOfHash(p_array_of_hash, p_key, p_value_to_remove){
    return p_array_of_hash.filter((l_cur_row) => {return l_cur_row[p_key] != p_value_to_remove});
}

And a sample usage:

l_test_arr = 
[
    {
	     post_id: 1,
		post_content: "Hey I am the first hash with id 1"
    },
 	{
	    post_id: 2,
    	post_content: "This is item 2"
 	},
    {
    	post_id: 1,
	    post_content: "And I am the second hash with id 1"
 	},
    {
    	post_id: 3,
    	post_content: "This is item 3"
    },
 ];



 l_test_arr = removeFromArrayOfHash(l_test_arr, "post_id", 2); // gives both of the post_id 1 hashes and the post_id 3
 l_test_arr = removeFromArrayOfHash(l_test_arr, "post_id", 1); // gives only post_id 3 (since 1 was removed in previous line)

Solution 12 - Javascript

with filter & indexOf

withLodash = _.filter(arrayOfObjects, (obj) => (listToDelete.indexOf(obj.id) === -1));
withoutLodash = arrayOfObjects.filter(obj => listToDelete.indexOf(obj.id) === -1);

with filter & includes

withLodash = _.filter(arrayOfObjects, (obj) => (!listToDelete.includes(obj.id)))
withoutLodash = arrayOfObjects.filter(obj => !listToDelete.includes(obj.id));

Solution 13 - Javascript

You can use filter. This method always returns the element if the condition is true. So if you want to remove by id you must keep all the element that doesn't match with the given id. Here is an example:

> arrayOfObjects = arrayOfObjects.filter(obj => obj.id != idToRemove)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDan KanzeView Question on Stackoverflow
Solution 1 - JavascriptRy-View Answer on Stackoverflow
Solution 2 - JavascriptparliamentView Answer on Stackoverflow
Solution 3 - JavascriptRahul R.View Answer on Stackoverflow
Solution 4 - JavascriptNaresh ChennuriView Answer on Stackoverflow
Solution 5 - JavascriptfatlinesofcodeView Answer on Stackoverflow
Solution 6 - JavascriptMiroslav SavovskiView Answer on Stackoverflow
Solution 7 - Javascriptuser2704940View Answer on Stackoverflow
Solution 8 - JavascriptFelix RabeView Answer on Stackoverflow
Solution 9 - JavascriptSylvain LerouxView Answer on Stackoverflow
Solution 10 - JavascriptSubhojit MondalView Answer on Stackoverflow
Solution 11 - JavascriptMehmet KaplanView Answer on Stackoverflow
Solution 12 - Javascriptuser3437231View Answer on Stackoverflow
Solution 13 - JavascriptDavid Benitez RibaView Answer on Stackoverflow