2013-06-22 25 views
47

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

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 
}); 
+0

不是。但是你可以直接处理Arrays原型的'filter()'方法;看起来更干净:) – gustavohenke

回答

58

如果你要使用这种模式有很多,你可以创建一个mixin像下面这样,虽然,它没有做任何事情比你原来的代码fundementally不同。它只是让开发人员更友好。

_.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]); 

更新 - 这上面的回答是旧的和笨重。请使用answer from Adam Boduch作为更优雅的解决方案。

_(collections) 
    .keyBy('id') // or .indexBy() if using lodash 3.x 
    .at(ids) 
    .value(); 
+0

你错过了keyBy的结束报价。我会纠正,但不会让我添加一个字符;) –

6

我喜欢jessegavin's答案,但我扩大它使用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深,或者你想为具有点在其名称属性的支持,这里有一个更多的防守和强大的版本:

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; 
} 
+3

lodash'get'默认情况下很深,因此您可以执行诸如__get(object,'a [0] .b.c')的操作;'。 所以你所要做的只是让@jessegavin回答支持深层属性是用'_.get(item,property)'改变'item [property]'。请参阅[lodash文档](https://lodash.com/docs#get)。 – danbars

34

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

_(collections) 
    .indexBy('id') 
    .at(ids) 
    .value(); 
+5

这个解决方案的精巧是出色的。而Lodash 4用户可以简单地用'keyBy'替换'indexBy',以便继续运行。 –

+2

如果'collections'不包含任何匹配'ids'的对象,它似乎会返回一个数组,其中包含一个未定义的元素。 '[undefined']。这会使我无法测试'someArray.length',因此我添加了一个'.filter()'_(集合).keyBy('id')。at(ids).filter()。value();' – steezeburger

12

我们还可以过滤这样

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); 
0

我注意到许多这些答案都是过时的或含有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' } ] 
0

这些答案并没有为我工作,因为我希望能在一个非唯一值过滤。如果您将keyBy更改为groupBy您可以通过。

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

我最初的用途是砸的东西,所以我换出pickomit

谢谢Adam Boduch为起点。