198

I have an object that looks like this:

var obj = {
    "objectiveDetailId": 285,
    "objectiveId": 29,
    "number": 1,
    "text": "x",
    "subTopics": [{
        "subTopicId": 1,
        "number": 1
    }, {
        "subTopicId": 2,
        "number": 32
    }, {
        "subTopicId": 3,
        "number": 22
    }]
}
var stToDelete = 2;

I have lodash installed in my application for other things. Is there an efficient way to use lodash to delete the entry: {"subTopicId":2, "number":32} from the obj object?

Or is there a javascript way to do this?

Tony Brasunas
  • 4,012
  • 3
  • 39
  • 51
Samantha J T Star
  • 30,952
  • 84
  • 245
  • 427
  • 1
    you can just use `splice` (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) to remove item from a list – z33m Jan 22 '14 at 11:15
  • 1
    Changed the title because removing 4 from an array [1,4,5] cannot be done this way. Yes, I do understand that arrays can be implemented from the hash/object and probably are, but there is a subtle difference in these two. To remove from an array you would use `result = _.pull(arr, value)` This would remove all the matching values from the list. – boatcoder Apr 28 '15 at 20:44

10 Answers10

303

As lyyons pointed out in the comments, more idiomatic and lodashy way to do this would be to use _.remove, like this

_.remove(obj.subTopics, {
    subTopicId: stToDelete
});

Apart from that, you can pass a predicate function whose result will be used to determine if the current element has to be removed or not.

_.remove(obj.subTopics, function(currentObject) {
    return currentObject.subTopicId === stToDelete;
});

Alternatively, you can create a new array by filtering the old one with _.filter and assign it to the same object, like this

obj.subTopics = _.filter(obj.subTopics, function(currentObject) {
    return currentObject.subTopicId !== stToDelete;
});

Or

obj.subTopics = _.filter(obj.subTopics, {subTopicId: stToKeep});
orad
  • 15,272
  • 23
  • 77
  • 113
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • 3
    The reason that this answer rocks is because you can use a *predicate function*, which is exactly what I was looking for. Removing an element is trivial if you know the index, but what about when you *don't* know the index? – random_user_name Jan 19 '16 at 23:30
  • 3
    Might be worth mentioning [_.filter](https://lodash.com/docs#filter) if you don't want to mutate the original array.... – random_user_name Jan 19 '16 at 23:33
  • @cale_b Thank you :-) Updated the answer with the `_.filter` version. – thefourtheye Jun 03 '16 at 04:28
  • 7
    @thefourtheye `_.filter ` return an element if the predicate is true. Your implementation will return all unwanted elements instead of those you want to keep – Xeltor Jun 14 '17 at 19:26
  • 6
    @thefourtheye you should use `_.reject` instead of `_.filter` to use the same predicate. Check [my answer](https://stackoverflow.com/a/44553188/1330674) for more details! – Xeltor Jun 14 '17 at 19:41
  • Awesome the idea of predicate works great in my current scenario – Sean Ch Sep 12 '18 at 16:49
29

Just use vanilla JS. You can use splice to remove the element:

obj.subTopics.splice(1, 1);

Demo

Andy
  • 61,948
  • 13
  • 68
  • 95
  • 14
    the user asks `Is there an efficient way to use _lodash to delete` – semirturgay Jan 22 '14 at 11:18
  • 7
    @Andy You are right, but what if the index is not known already? – thefourtheye Mar 05 '15 at 08:50
  • 4
    splice() is the best approach if you want your array to be mutated. If you use remove then it returns the new array and this has to be reassigned. – omarjebari Sep 21 '18 at 09:33
  • If you wish to remove an item from an array by its index in the array (obviously, you have this index if you want to perform the remove action in this way), then using the splice method is the most efficient (and easy) way to do it. No need for comparing anything and making the code more complicated and vulnerable for bugs and errors... – TheCuBeMan Oct 14 '18 at 11:30
28

you can do it with _pull.

_.pull(obj["subTopics"] , {"subTopicId":2, "number":32});

check the reference

semirturgay
  • 4,151
  • 3
  • 30
  • 50
  • 7
    Per the docs, [`_.pull`](https://lodash.com/docs#pull) uses *strict equality for comparisons, i.e. ===*. Two different plain objects will never compare as equal by `===` (or by `==` for that matter). Thus your code above will never remove any elements from the array. – Mark Amery Oct 09 '14 at 13:51
  • 1
    Yet, that's the only one that works with strings in array. `_.remove` just flushes the array. – Yauheni Prakopchyk Dec 17 '15 at 12:57
  • 3
    I still think this is the right answer. JS .filter removes all elements matching, JS .splice requires that I know the index, _.remove iterates over all elements of the array thus being less efficient. _.pull is exactly what I want: _.pull(array, itemToRemove). – Judah Gabriel Himango Jul 27 '16 at 14:31
28

You can now use _.reject which allows you to filter based on what you need to get rid of, instead of what you need to keep.

unlike _.pull or _.remove that only work on arrays, ._reject is working on any Collection

obj.subTopics = _.reject(obj.subTopics, (o) => {
  return o.number >= 32;
});
Xeltor
  • 4,626
  • 3
  • 24
  • 26
  • In addition to this answer, the original array is never mutated, and easier to read when setting up conditional logic on your return statements. – klewis Jun 28 '22 at 15:37
17

The easiest and most convenient way -

_.without([2, 1, 2, 3], 1, 2);
// => [3]

_.without documentation.

lejlun
  • 4,140
  • 2
  • 15
  • 31
Farhan Syed
  • 177
  • 1
  • 5
9

There are four ways to do this as I know

const array = [{id:1,name:'Jim'},{id:2,name:'Parker'}];
const toDelete = 1;

The first:

_.reject(array, {id:toDelete})

The second one is :

_.remove(array, {id:toDelete})

In this way the array will be mutated.

The third one is :

_.differenceBy(array,[{id:toDelete}],'id')
// If you can get remove item 
// _.differenceWith(array,[removeItem])

The last one is:

_.filter(array,({id})=>id!==toDelete)

I am learning lodash

Answer to make a record, so that I can find it later.

mqliutie
  • 377
  • 2
  • 17
2

In Addition to @thefourtheye answer, using predicate instead of traditional anonymous functions:

  _.remove(obj.subTopics, (currentObject) => {
        return currentObject.subTopicId === stToDelete;
    });

OR

obj.subTopics = _.filter(obj.subTopics, (currentObject) => {
    return currentObject.subTopicId !== stToDelete;
});
orad
  • 15,272
  • 23
  • 77
  • 113
Pranav Singh
  • 17,079
  • 30
  • 77
  • 104
1

lodash and typescript

const clearSubTopics = _.filter(obj.subTopics, topic => (!_.isEqual(topic.subTopicId, 2)));
console.log(clearSubTopics);
Uliana Pavelko
  • 2,824
  • 28
  • 32
0

Here is the simple lodash function with array and deleting it with the index number.

index_tobe_delete = 1

fruit = [{a: "apple"}, {b: "banana"}, {c: "choco"}]
_.filter(fruit, (value, key)=> {
return (key !== index_tobe_delete)
})
Anupam Maurya
  • 1,927
  • 22
  • 26
0

You can use removeItemFromArrayByPath function which includes some lodash functions and splice

/**
 * Remove item from array by given path and index
 *
 * Note: this function mutates array.
 *
 * @param {Object|Array} data (object or array)
 * @param {Array|String} The array path to remove given index
 * @param {Number} index to be removed from given data by path
 *
 * @returns {undefined}
 */

const removeItemFromArrayByPath = (data, arrayPath, indexToRemove) => {
  const array = _.get(data, arrayPath, []);
  if (!_.isEmpty(array)) {
    array.splice(indexToRemove, 1);
  }
};

You can check the examples here: https://codepen.io/fatihturgut/pen/NWbxLNv

Fatih Turgut
  • 319
  • 3
  • 9