2013-06-22 4 views
47

Я хотел бы отфильтровать коллекцию, используя массив значений свойства. Учитывая массив идентификаторов, возвращайте объекты с соответствующими идентификаторами. Есть ли способ быстрого доступа с использованием 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

Не совсем.Но вы можете напрямую обращаться к методу 'filter()' прототипов массивов; выглядит чище :) – gustavohenke

ответ

58

Если вы собираетесь использовать этот вид рисунка много, то вы можете создать подмешать как следующий, хотя, это не делает ничего 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]); 

Update - Это выше ответ стар и неуклюжим. Пожалуйста, используйте answer from Adam Boduch для более элегантного решения.

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

вам не хватает конечной цитаты на keyBy. Я бы исправил, но SO не позволит мне добавить один символ;) –

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 ответить на глубокие свойства, - это изменение 'item [property]' с '_.get (item, property)'. См. [Lodash documents] (https://lodash.com/docs#get). – danbars

34

Конкретный раствор lodash, который использует indexBy() и at().

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

Эта гордость этого решения великолепна. Пользователи Lodash 4 могут просто заменить 'indexBy' на' keyBy', чтобы продолжить работу. –

+2

Если 'коллекции' не содержат каких-либо объектов, которые совпадают с' 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(); 

Моя первоначальное использование было падение вещи, поэтому я выключил pick с omit.

Спасибо Adam Boduch за отправную точку.