2015-04-30 8 views
11

Questa domanda è specifica per lodash.lodash: filtro array di oggetti con una diversa serie di oggetti

Dato due matrici di oggetti, qual è il modo migliore per filtrare un array con gli oggetti dell'altro array? Ho tentato di creare uno scenario qui sotto, e il modo in cui ho fatto questo è usare due loop .forEach, ma mi piacerebbe sapere se usando lodash c'è un modo migliore per andare su questo tipo di filtro.


Esempio
La matrice principale fonte di oggetti è users.

var users = [ 
    { 'user': 'barney', 'age': 36, 'active': true }, 
    { 'user': 'joe', 'age': 40, 'active': false }, 
    { 'user': 'fred', 'age': 50, 'active': false }, 
    { 'user': 'fred', 'age': 60, 'active': false }, 
    { 'user': 'fred', 'age': 70, 'active': false }, 
    { 'user': 'fred', 'age': 22, 'active': false }, 
    { 'user': 'fred', 'age': 25, 'active': false }, 
    { 'user': 'barney', 'age': 40, 'active': false }, 
    { 'user': 'pebbles', 'age': 1, 'active': true } 
]; 

La matrice di oggetti che filtri l'array users è chiamato others.

var others = [ 
    { 'user': 'fred', 'age': 60 }, 
    { 'user': 'fred', 'age': 70}, 
    { 'user': 'fred', 'age': 22} 
]; 

Il risultato desiderato basato su others filtraggio users è:

[ 
    { 'user': 'fred', 'age': 60, 'active': false }, 
    { 'user': 'fred', 'age': 70, 'active': false }, 
    { 'user': 'fred', 'age': 22, 'active': false } 
]; 

Ecco un modo per ottenere il risultato desiderato.

var result = []; 

_.forEach(users, function (n, key) { 
    _.forEach(others, function (n2, key2) { 
     if (n.user === n2.user && n.age === n2.age) { 
     result.push(n); 
     } 
    }); 
}); 

console.log(result); 

Ecco l'esempio su jsbin.
http://jsbin.com/hapariviya/1/edit?html,js,console,output

+0

si sta cercando di trovare i duplicati in base all'utente e l'età? –

+0

@CoryDanielson - cercando di trovare le corrispondenze in base all'utente e alle proprietà dell'età. Lo definirei corrispondente, non duplicato. – mg1075

+1

È interessante notare che la tua soluzione originale è di gran lunga la più veloce. Penso che potrebbe produrre duplicati se altri hanno duplicati, ma se restituite false; dopo aver eseguito 'result.push (n)' dovrebbe essere ok. –

risposta

6

È possibile indicizzare gli altri e quindi ottenere i risultati desiderati senza dover annidare i cicli. Dovrebbe essere una soluzione relativamente efficiente, indipendentemente dalla quantità di dati:

// index others by "user + age" 
var lookup = _.keyBy(others, function(o) { return o.user + o.age.toString() }); 
// find all users where "user + age" exists in index, one loop, quick lookup. no nested loops 
var result = _.filter(users, function(u) { 
    return lookup[u.user + u.age.toString()] !== undefined; 
}); 

Questo dà lo stesso risultato:

[ 
    { 'user': 'fred', 'age': 60, 'active': false }, 
    { 'user': 'fred', 'age': 70, 'active': false }, 
    { 'user': 'fred', 'age': 22, 'active': false } 
]; 

È interessante notare che la soluzione originale è stato il più performante di tutte queste risposte.

http://jsperf.com/testingdiwq

I problemi di prestazioni sono piuttosto trascurabili qui. Nella maggior parte dei casi, l'interazione DOM è il collo di bottiglia principale delle prestazioni del front-end. Se dovessi eseguire questo contro enormi set di dati e notato il blocco, vorresti sicuramente ottimizzarlo ulteriormente usando cicli for anziché eseguire iterazioni con le funzioni di lodash .... ma in genere non troverai quel tipo di dati in JavaScript ... SQL e altri lo gestiranno meglio.

+0

Hmmm, la creazione della stringa di ricerca come una sorta di "stringa magica" potrebbe portare a problemi involontari? Per ragioni, supponiamo che gli utenti siano numeri interi e che tu abbia utente 1 e utente 11 e che l'utente 1 abbia 11 anni e che l'utente 11 abbia 1 anno? Ovviamente questo non è realistico nella struttura attuale dei dati, ma non potrebbe esistere questo tipo di mis-match in questo formato? – mg1075

+0

Sì, questo potrebbe sicuramente accadere in queste circostanze. Dovresti fare un albero o qualcosa per essere al sicuro da quel tipo di problema. Il guadagno in termini di prestazioni è trascurabile, sebbene ... a meno che non venga eseguito su un insieme di dati molto ampio, ma in tal caso dovresti passare a cicli for per ottenere buone prestazioni. –

+0

Nella tua stringa magica, potresti anche usare un separatore tra il valore dell'utente e il valore dell'età, ad esempio "utente11-11" dove "-" divide l'utente ed età, per evitare quel tipo di problema –

7

Ecco modo più pulito che posso pensare:

var result = _.flatten(_.map(others, function(item){ 
    return _.filter(users, item); 
})); 

Edit: Scuse JS Bin uscita è stata offuscando l'array nidificato.

+0

La sintassi è piacevole e breve, ma in realtà non restituisce il risultato desiderato. Il risultato desiderato è una matrice di oggetti, non una matrice di matrici. Il risultato qui è una matrice di matrici. – mg1075

+0

Grazie; ora restituendo oggetti. – mg1075

2
var result = _.flatten(_.map(others, function(other){return _.where(users, other);})); 
2

Utilizzando le frecce di grasso ES6 e lodash del rifiutano:

const result = _.reject(users, (item) => _.find(others, { user: item.user })); 
Problemi correlati