2013-06-22 59 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爲起點。