2015-04-30 19 views
11

To pytanie jest specyficzne dla lodash.lodash: filtruj tablicę obiektów o innej tablicy obiektów.

Który z dwóch tablic obiektów jest najlepszy, aby filtrować jedną tablicę z obiektami innej macierzy? Próbowałem przedstawić poniżej scenariusz, a sposób, w jaki to zrobiłem, polega na użyciu dwóch pętli .forEach, ale chciałbym się dowiedzieć, czy używanie LASA jest lepszym sposobem na obejście tego typu filtrowania.


Przykład
Głównym źródłem tablicy obiektów jest 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 } 
]; 

Tablica obiektów filtruje tablicę users nazywa others.

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

Pożądany wynik podstawie others filtrowania users jest:

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

Tu jest jednym ze sposobów, aby uzyskać żądany wynik.

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

Oto przykład na jsbin.
http://jsbin.com/hapariviya/1/edit?html,js,console,output

+0

Starasz się znaleźć duplikaty w oparciu o użytkownika i wieku? –

+0

@CoryDanielson - próba znalezienia dopasowań na podstawie właściwości użytkownika i wieku. Nazwałbym to dopasowywaniem, a nie duplikowaniem. – mg1075

+1

Co ciekawe, twoje oryginalne rozwiązanie jest zdecydowanie najszybsze. Myślę, że mógłby produkować duplikaty, jeśli inni mają duplikaty, ale jeśli "zwrócisz false", po wykonaniu 'result.push (n)' powinno być w porządku. –

Odpowiedz

6

Można indeksować pozostałe, a następnie uzyskać pożądane wyniki bez konieczności zagnieżdżania pętli. Powinien on być stosunkowo wydajne rozwiązanie, niezależnie od ilości danych:

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

To daje ten sam wynik:

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

ciekawe, oryginalny rozwiązanie było najbardziej wydajnych wszystkich tych odpowiedzi.

http://jsperf.com/testingdiwq

obawy wydajności są tutaj dość znikoma. W większości przypadków interakcja DOM jest głównym wąskim gardłem wydajności w interfejsie użytkownika. Jeśli miałbyś uruchomić to z dużymi zbiorami danych i zauważyłbyś blokowanie, z pewnością chcesz zoptymalizować go dalej, używając pętli zamiast iterowania za pomocą funkcji lodash ... ale zazwyczaj nie natrafisz na takie dane w JavaScript ... SQL i inni poradziliby sobie z tym lepiej.

+0

Hmmm, czy tworzenie ciągów wyszukiwania jako rodzaju "magicznej struny" może prowadzić do nieumyślnych problemów? Dla przykładu, załóżmy, że użytkownicy są liczbami całkowitymi i masz użytkownika 1 i użytkownika 11, a użytkownik 1 ma 11 lat, a użytkownik 11 ma 1 rok życia? Oczywiście nie jest to realistyczne w obecnej strukturze danych, ale czy ten rodzaj niezgodności nie istnieje w tym formacie? – mg1075

+0

Tak, może się to zdarzyć w takich okolicznościach. Musiałbyś zrobić drzewo lub coś, co byłoby bezpieczne przed tego rodzaju problemami. Wzrost wydajności jest znikomy, chociaż ... chyba że jest to wykonywane w bardzo dużym zestawie danych, ale w takim przypadku musisz przełączyć się na pętle dla uzyskania dobrej wydajności. –

+0

W twoim magicznym łańcuchu możesz również użyć separatora między użytkownikiem a wartością wieku, np. "User11-11" gdzie "-" dzieli użytkownika i wiek, aby uniknąć tego rodzaju problemu –

7

Oto przejrzysty sposób mogę myśleć:

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

Edit: Przeprosiny JS Bin wyjściowa została kasował zagnieżdżony tablicę.

+0

Składnia jest dobra i krótka, ale w rzeczywistości nie zwraca pożądanego wyniku. Pożądanym wynikiem jest tablica obiektów, a nie tablica tablic. Rezultatem jest tablica tablic. – mg1075

+0

Dzięki; teraz zwracające obiekty. – mg1075

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

Korzystanie ES6 strzałki tłuszczu i lodash odrzucanych:

const result = _.reject(users, (item) => _.find(others, { user: item.user })); 
Powiązane problemy