61

我想使用属性值数组过滤集合。给定一个 ID 数组,返回具有匹配 ID 的对象。有没有使用lodash/的快捷方法underscore

var collections = [{ id: 1, name: 'xyz' },
                   { id: 2,  name: 'ds' },
                   { id: 3,  name: 'rtrt' },
                   { id: 4,  name: 'nhf' },
                   { id: 5,  name: 'qwe' }];
var ids = [1,3,4];

// This works, but any better way?

var filtered = _.select(collections, function(c){    
    return ids.indexOf(c.id) != -1
});
4

7 回答 7

66

如果您要经常使用这种模式,您可以创建一个如下所示的 mixin,但是,它与您的原始代码没有任何根本不同。它只是使它对开发人员更加友好。

_.mixin({
  'findByValues': function(collection, property, values) {
    return _.filter(collection, function(item) {
      return _.contains(values, item[property]);
    });
  }
});

然后你可以像这样使用它。

var collections = [
    {id: 1, name: 'xyz'}, 
    {id: 2,  name: 'ds'},
    {id: 3,  name: 'rtrt'},
    {id: 4,  name: 'nhf'},
    {id: 5,  name: 'qwe'}
];

var filtered = _.findByValues(collections, "id", [1,3,4]);

更新- 上面的答案既旧又笨重。请使用Adam Boduch 的答案以获得更优雅的解决方案。

_(collections)
  .keyBy('id') // or .indexBy() if using lodash 3.x
  .at(ids)
  .value();
于 2013-09-16T14:49:18.763 回答
47

使用indexBy()at()的简洁 lodash 解决方案。

// loDash 4
_.chain(collections)
 .keyBy('id')
 .at(ids)
 .value();

// below loDash 4
_(collections)
 .indexBy('id')
 .at(ids)
 .value();
于 2015-11-23T18:40:25.653 回答
19

我们也可以这样过滤

var collections = [{ id: 1, name: 'xyz' },
            { id: 2,  name: 'ds' },
            { id: 3,  name: 'rtrt' },
            { id: 4,  name: 'nhf' },
            { id: 5,  name: 'qwe' }];



        var filtered_ids = _.filter(collections, function(p){
            return _.includes([1,3,4], p.id);
        });

        console.log(filtered_ids);
于 2016-06-15T11:23:14.147 回答
10

这对我很有用:

let output = _.filter(collections, (v) => _.includes(ids, v.id));
于 2018-04-20T21:50:17.427 回答
7

我喜欢jessegavin 的回答,但我使用lodash-deep对其进行了扩展以进行深度属性匹配。

var posts = [{ term: { name: 'A', process: '123A' } }, 
             { term: { name: 'B', process: '123B' } }, 
             { term: { name: 'C', process: '123C' } }];

var result = _.filterByValues(posts, 'term.process', ['123A', '123C']);
// results in objects A and C to be returned

jsFiddle

_.mixin({
    'filterByValues': function(collection, key, values) {
        return _.filter(collection, function(o) {
            return _.contains(values, resolveKey(o, key));
        });
    }
});

function resolveKey(obj, key) {
    return (typeof key == 'function') ? key(obj) : _.deepGet(obj, key);
}

如果您不信任 lodash-deep 或者您希望支持名称中带有点的属性,那么这里有一个更具防御性和健壮性的版本:

function resolveKey(obj, key) {
    if (obj == null || key == null) {
        return undefined;
    }
    var resolved = undefined;
    if (typeof key == 'function') {
        resolved = key(obj);
    } else if (typeof key == 'string' ) {
        resolved = obj[key];
        if (resolved == null && key.indexOf(".") != -1) {
            resolved = _.deepGet(obj, key);
        }
    }
    return resolved;
}
于 2015-01-27T14:54:11.267 回答
3

这些答案对我不起作用,因为我想过滤非唯一值。如果你换成keyBygroupBy可以过得去。

_(collections)
  .groupBy(attribute)
  .pick(possibleValues)
  .values()
  .flatten()
  .value();

我最初的用途是丢弃东西,所以我pickomit.

感谢Adam Boduch的起点。

于 2017-11-20T17:25:57.977 回答
1

我注意到其中许多答案已经过时或包含 Lodash 文档中未列出的辅助功能。接受的答案包括不推荐使用的功能_.contains,应该更新。

所以这是我的 ES6 答案。

基于Lodash v4.17.4

_.mixin( {
    filterByValues: ( c, k, v ) => _.filter(
        c, o => _.indexOf( v, o[ k ] ) !== -1
    )
} );

并这样调用:

_.filterByValues(
    [
        {
            name: 'StackOverflow'
        },
        {
            name: 'ServerFault'
        },
        {
            name: 'AskDifferent'
        }
    ],
    'name',
    [ 'StackOverflow', 'ServerFault' ]
);

// => [ { name: 'StackOverflow' }, { name: 'ServerFault' } ]
于 2017-10-26T13:41:25.607 回答