2013-06-22 10 views
47

Vorrei filtrare una raccolta utilizzando l'array del valore della proprietà. Dato un array di ID, restituisci gli oggetti con ID corrispondenti. Esiste un metodo di scelta rapida utilizzando lodash/underscore?elenco dei filtri di lodash utilizzando una serie di valori

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

Non proprio.Ma potresti trattare direttamente con il metodo 'filter()' dei prototipi di Array; sembra più pulito :) – gustavohenke

risposta

58

Se avete intenzione di utilizzare questo tipo di modello molto, si potrebbe creare un mixin come il seguente, però, non è facendo nulla fundementally diverso da quello del codice originale. Rende solo più sviluppatore amichevole.

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

Quindi è possibile utilizzarlo in questo modo.

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

Aggiornamento - Questa risposta di cui sopra è vecchio e goffo. Si prega di utilizzare il answer from Adam Boduch per una soluzione molto più elegante.

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

ti manca la citazione finale su keyBy. Correggerò ma SO non mi consentirà di aggiungere un singolo carattere;) –

6

mi piace jessegavin's risposta, ma ho ampliato su di esso utilizzando lodash-deep per la corrispondenza di proprietà profondo.

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

Se non vi fidate lodash profondo o se si vuole il supporto per le proprietà che hanno i puntini nei loro nomi, ecco una versione più difensiva e robusto:

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' è profondo per impostazione predefinita, quindi puoi fare cose come' _.get (oggetto, 'a [0] .b.c') ; '. Quindi tutto quello che dovete fare per rendere @jessegavin risposta alle proprietà deep support è la modifica 'item [proprietà]' con '_.get (oggetto, proprietà)'. Vedi [documenti di lodash] (https://lodash.com/docs#get). – danbars

34

Una soluzione lodash concisa che utilizza indexBy() e at().

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

Questa pessità di questa soluzione è splendida. E gli utenti di Lodash 4 possono semplicemente sostituire 'indexBy' con' keyBy' per continuare a funzionare. –

+2

Se 'collections' non contiene oggetti che corrispondono a' ids', sembra che restituisca un array con un elemento di indefinito. '[Undefined']. Questo fallisce il mio test go di 'someArray.length' quindi ho aggiunto un' .filter() ' ' _ (collezioni) .keyBy ('id'). A (ids) .filter(). Value(); ' – steezeburger

12

Possiamo anche filtrare come questo

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

ho notato molte di queste risposte sono obsoleti o contengono funzioni ausiliarie non elencati nella documentazione Lodash. La risposta accettata include la funzione deprecata _.contains e dovrebbe essere aggiornata.

Quindi ecco la mia risposta ES6.

Basato su Lodash v4.17.4

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

e invocato come tale:

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

// => [ { name: 'StackOverflow' }, { name: 'ServerFault' } ] 
0

Queste risposte non hanno funzionato per me, perché volevo filtrare su un valore non univoco. Se si modifica keyBy a groupBy è possibile ottenere.

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

Il mio uso iniziale era quello di cadere le cose, così ho acceso fuori pick con omit.

Grazie Adam Boduch per il punto di partenza.

Problemi correlati