underscore icon indicating copy to clipboard operation
underscore copied to clipboard

Feature request: _.deleteWhere

Open morgoth opened this issue 10 years ago • 16 comments

Currently having array of objects, to delete one of them I need to write:

var collection = [{id: 1}, {id: 3}];
var objectToRemove = _.findWhere(collection, function (obj) { return obj.id === 3 });
var objectIndex = collection.indexOf(objectToRemove);
collection.splice(objectIndex, 1);

It would be nice to have in underscore something like:

_.deleteWhere(collection, {id: 2})

If you find this useful I can try to implement it and send a PR.

morgoth avatar Sep 18 '14 11:09 morgoth

One of Underscore's philosophies is to expose reusable, composable methods so you can implement these types of special functions yourself, keeping the library small and purposefully managed. It should be fairly easy to do in your own copy with mixin.

_.mixin({
  deleteWhere: function(collection, predicate) {
    var obj = _.findWhere(collection, predicate);
    collection.splice(_.indexOf(collection, obj), 1);
  }
});

_.deleteWhere(collection, {id: 2});

akre54 avatar Sep 18 '14 14:09 akre54

@akre54 It gets a bit trickier when you want to remove all matches and isn't something devs can compose easily.

@morgoth You can find this method in Lo-Dash as _.remove, (_.remove(array, {id: 2}), or as an individual method npm package. I'm sure there's others on npm too.

If you go the _.mixin route, implementing it on your own, you can leverage Underscore's new _.iteratee method to support callbacks as well as "_.pluck" & "_where" callback shorthands.

@joshuacc Have y'all considered array/object mutator methods for underscore-contrib? It's one of those things that seems to come up from time to time.

Related to #1848.

jdalton avatar Sep 18 '14 14:09 jdalton

@jdalton Not so far, but it sounds reasonable to me. This example in particular seems quite useful. I'll create an issue to track it.

joshuacc avatar Sep 19 '14 02:09 joshuacc

I think this would be a nice function to add to Underscore...

jashkenas avatar Sep 19 '14 20:09 jashkenas

Usefulness or niceness aside, it fits closer to a mixin or underscore.contrib than a core underscore method.

akre54 avatar Sep 19 '14 20:09 akre54

It's not a functional method but other libs like Mootools have this as well

I'd :+1: this addition

megawac avatar Sep 19 '14 20:09 megawac

The problem is, ideally we'd also include a more generic .delete that takes an array and a reference to an object, but that's not much more than sugar over arr.splice(.indexOf(arr, obj), 1)). It could be composed with findWhere, but I'm not sure the extra abstraction (and the addition to the Underscore API) is worth it.

On Fri, Sep 19, 2014 at 4:52 PM, Graeme Yeates [email protected] wrote:

It's not a functional method but other libs like Mootools http://mootools.net/docs/core/Types/Array#Array:erase have this as well

I'd [image: :+1:] this addition

— Reply to this email directly or view it on GitHub https://github.com/jashkenas/underscore/issues/1856#issuecomment-56233853 .

akre54 avatar Sep 19 '14 20:09 akre54

I think of it more like a friend of _.reject, because it removes any element the predicate returns truthy for, but it mutates the array.

jdalton avatar Sep 19 '14 21:09 jdalton

It's not the most trivial thing to implement if you want to remove all matches cause of splice. Quick port based on MooTools docs

_.deleteWhere = function(list, what) {
     var predicate = _.iteratee(what), index = this.length;
     while(index--) {
           if (predicate(list[index], index, list) this.splice(index,1);
     }
     return list;
} 

megawac avatar Sep 19 '14 21:09 megawac

The name _.deleteWhere is a bit gross. You don't have _.filterWhere or _.rejectWhere and _.delete on its own may require brackets, _['delete'] in some environments which is why I prefer _.remove.

jdalton avatar Sep 19 '14 21:09 jdalton

Problem is iteratee won't work here, because you could be passing a hash of properties to match against, or you could be passing an object to compare by ref equality (or string, etc).

There were plenty of things mootools did because they didn't know any better. One of Underscores greatest strengths is a terse API, and it becomes hard to get rid of methods this once it's added.

akre54 avatar Sep 19 '14 21:09 akre54

Problem is iteratee won't work here

Naw, think of it like _.reject, but instead of returning a new array, it returns the mutated array.

One of Underscores greatest strengths is a terse API, and it becomes hard to get rid of methods this once it's added.

Open it up to a poll. Jeremy could tweet the poll (I'm sure there's a nice poll service somewhere) and then see if there's an opinion one way or the other from users.

jdalton avatar Sep 19 '14 21:09 jdalton

My bad. That was unnecessary. But keeping a level-headed and intelligent design philosophy is essential in as small a library as underscore.

akre54 avatar Sep 19 '14 21:09 akre54

Design by committee. Brilliant!

It's simply testing the waters to see if Underscore's users have a strong opinion one way or another. It's a data point to consider when determining if something like this is a good fit for Underscore.

I find methods like _.remove useful, but maybe others don't. I can see being hesitant about expanding mutator methods beyond _#pop, _#push, _#shift, _#splice, & _#unshift because it's not something Underscore has tackled. In 2 years I've only added 2 array mutator methods (_.pull & _.remove).

jdalton avatar Sep 19 '14 21:09 jdalton

Bumping this because I ran into the need for it again today,

var Layer = Backbone.Model.extend({}, {
   isValid(settings) {
       return _.has(settings, "layerType");
   }
});

var LayerCollection = Backbone.Collection.extend({
     model: Layer,
     initialize(layers) {
        _.remove(layers, _.negate(Layer.isValid));
    }
});

new LayerModel([
   {name: "layer1", layerType: "position"},
   {name: "layer2", layerType: "path"},
   {name: "invalid"}
]);

megawac avatar Dec 17 '14 18:12 megawac

Sure @megawac -- go for it. _.remove is a fine name.

jashkenas avatar Dec 18 '14 18:12 jashkenas