2012-01-13 10 views
15

Często potrzebuję przeszukiwać tablicę javascript zawierającą obiekty. Chcę wyszukać obiekt w tablicy, która ma dopasowanie właściwości. Na przykład, przeszukując tablicę obiektów Person dla miejsca, w którym identyfikator/klucz osoby === "ABC123"Czy istnieje lepszy sposób wyszukiwania tablicy JavaScript niż przy użyciu jQuery?

Można to zrobić całkiem łatwo za pomocą jQuery za pomocą metody $ .each, na której się zdecydowałem. Możesz zobaczyć przykład tutaj w jsFiddle. http://jsfiddle.net/johnpapa/EJAFG/

Zastanawiam się, czy ktoś inny znalazł szybszy i/lub lepszy sposób na zrobienie tego?

var Person = function(code, name) { 
    this.code = code; 
    this.name = name; 
}; 
var people = [ 
    new Person("ABC123", "Tooth Fairy"), 
    new Person("DEF456", "Santa Claus"), 
    new Person("PIR000", "Jack Sparrow"), 
    new Person("XYZ987", "Easter Bunny") 
    ]; 

var utils = {}; 
// Could create a utility function to do this 
utils.inArray = function(searchFor, property) { 
    var retVal = -1; 
    $.each(this, function(index, item) { 
     if (item.hasOwnProperty(property)) { 
      if (item[property].toLowerCase() === searchFor.toLowerCase()) { 
       retVal = index; 
       return false; 
      } 
     } 
    }); 
    return retVal; 
}; 

// or we could create a function on the Array prototype indirectly 
Array.prototype.inArray = utils.inArray; 

// let's use the prototype for now 
var i = people.inArray("PIR000", "code"); 
$('#output').text(people[i].name); 

Istnieje wiele jest pytań podobnych do tego, ale muszę jeszcze zobaczyć jedną z roztworem innej niż iteracji (tak jak ja tutaj).

Pytanie brzmi: czy istnieje lepszy sposób?

+0

Jest podobne pytanie [tutaj] [1]. [1]: http://stackoverflow.com/questions/1144423/jquery-selectors-for-plain-javascript-objects-instead-of-dom-elements –

+0

Patrz http://stackoverflow.com/questions/143847/best-way-to-find-an-item-in-a-javascript-array i http://stackoverflow.com/questions/237104/array-containsobj-in-javascript – j08691

+0

@ j08691 oba te sprawdzają, czy istnieje dokładne dopasowanie obiektu. Dla tych, $ .inArray działa dobrze. Szukam wyszukiwania według klucza. –

Odpowiedz

16

$ .each byłoby o O (n) Myślę. Każda prosta pętla "for", która ulegnie uszkodzeniu po znalezieniu odpowiedniego elementu, będzie wynosić co najwyżej O (n), ale średnio będzie mniejsza, chyba że te ostatnie elementy tablicy będą stale uznawane za pasujące elementy. Array.filter to metoda, która działa, ale nie jest natywna dla niektórych przeglądarek. Istnieją czyste implementacje javascript metody Array.filter, jeśli chcesz ją użyć. Dla przeglądarek, które hostują go natywnie, prawdopodobnie wykonałoby się to szybciej, ponieważ ich implementacja została prawdopodobnie skompilowana i uruchomiona w natywnym kodzie. Ale metoda filtrująca zawsze dawałaby O (n), ponieważ "filtruje" elementy tablicy do nowej tablicy.

Osobiście trzymam się podejścia for (int i = 0; ...). Zmniejszenie zakresu zmiany zakresu przez wywołanie innych funkcji i łatwe "przełamanie" dopasowanego elementu.

Chciałbym również dodać, że można użyć lokalnego magazynu bazy danych (który korzysta z SqlLite) dostarczonego przez HTML 5. Oczywiście nie jest on szeroko obsługiwany, ale byłby DUŻO szybszy niż jakakolwiek inna metoda javascript, biorąc pod uwagę wystarczająco duży zestaw danych. Oto link, jeśli chcesz to sprawdzić:

http://blog.darkcrimson.com/2010/05/local-databases/

tutaj jest trochę off sposób ściana robi: można teoretycznie może indeksować dane i pobrać go za pomocą tych indeksów w szybkim sposób. Zamiast przechowywać dane w tablicy javascript, przechowujesz je w DOM i "indeksujesz" elementy używając klas CSS, takich jak "data-id-5". Daje to przewagę korzystania z wbudowanego interfejsu API selektora macierzystego w większości głównych przeglądarek. Oto przykład:

DOM:

<div id="datastuff" style="display:none"> 
    <span class="data-id-ABC123" data-person='{"code": "ABC123", "name": "Tooth Fairy"}'></span> 
    <span class="data-id-DEF456" data-person='{"code": "DEF456", "name": "Santa Claus"}'></span> 
    <span class="data-id-PIR000" data-person='{"code": "PIR000", "name": "Jack Sparrow"}'></span> 
    <span class="data-id-XYZ987" data-person='{"code": "XYZ987", "name": "Easter Bunny"}'></span> 
</div> 

Teraz możemy użyć jQuery i zapytanie o nim: Będziemy zapytać o klucz "abc123":

var person = $(".data-id-ABC123").data("person"); 
console.log(person.name);//Tooth Fairy 
+0

+1 za dobrą radę. Prosta pętla for jest prawdopodobnie czystsza (brak zależności od biblioteki zewnętrznej) i szybsza (mniej wywołań funkcji, brak tworzenia obiektów jQuery), ale kryteria OP mogą być różne. Jeśli jest to operacja wykonywana często na dużej tablicy, prosty indeks jest niewielkim obciążeniem dla dodania nowego obiektu, który może znacznie zwiększyć wydajność podczas wyszukiwania. – RobG

+0

+1 @odie Dzięki za wejście. Skłania mnie do myślenia albo o pętli, albo o $ .each jest w porządku. Jest to poszukiwanie, więc nie ma magicznej kuli. To po prostu miło odbiło się od pomysłów :) –

+1

Dodałem jeszcze jeden sposób, który bez wątpienia byłby niesamowicie szybki i bezpośredni technicznie bez pętli. Zmień indeks, aby używał identyfikatora Id, a możesz po prostu pobrać ElemById ("data-id-ABC123"), który w większości przypadków jest prawie przypadkowym procesem. – doogle

0

Może ty zapętlaj go za pomocą for a..in. Patrz: http://www.w3schools.com/js/js_loop_for_in.asp. Działa w podobny sposób jak foreach php.

+1

"Zakładam", że for/in jest taki sam jak $ .each ... ale może się mylę. Warte spróbowania. –

+0

for-in to * nie * foreach. Nie * używaj * go do iteracji na tablicach. Ponadto, [nie łącz] (http://w3fools.org) do w3schools – hugomg

+0

Nie powiedziałeś, że są takie same, ale dlaczego nie użyć go do iteracji tablicy? Dziękujemy za heads-up o www.w3fools.com. Twoje i ich punkt jest ważny, na pewno po przeczytaniu strony. – Ruben

6

To nie odpowiada na pytanie "szukaj" jako takie, ale może być rozwiązaniem dla Ciebie. Możesz utworzyć wyspecjalizowaną klasę PersonArray, która indeksuje znajdujące się w niej osoby. Wydajność z tym podejściem to O (1), ale wykorzystuje więcej pamięci.

var PersonArray = function(persons) { 
    this.elements = {}; 
    var i; 
    for (i=0; i < persons.length; i++) { 
     this.elements[persons[i].code] = persons[i]; 
    } 
}; 

PersonArray.prototype.fromCode = function(s) { 
    return this.elements[s]; 
}; 

var people = new PersonArray([ 
    new Person("ABC123", "Tooth Fairy"), 
    new Person("DEF456", "Santa Claus"), 
    new Person("PIR000", "Jack Sparrow"), 
    new Person("XYZ987", "Easter Bunny") 
    ]); 

console.log(people.fromCode("ABC123")); // Prints a person 
console.log(people.fromCode("DEF456")); // Prints a person 
console.log(people.fromCode("NONE")); // Undefined 

Można również rozszerzyć to podejście do indeksowania innych pól.

Zobacz również: a demo i (z 100 000 elementów).

7

Ogólnie rzecz biorąc nie można uzyskać elementów z tablicy szybciej niż O (n), chyba że wiesz coś o tym, co chcesz zindeksować.

Na przykład, jeśli indeksujesz coś porównywalnego, możesz posortować tablicę i wykonać wyszukiwanie binarne.

Jeśli przeprowadzasz wyszukiwanie w kolumnie, a wartości to int lub string, możesz użyć zwykłych obiektów JavaScript jako tabel mieszających.

var people = [ 
    new Person("ABC123", "Tooth Fairy"), 
    new Person("DEF456", "Santa Claus"), 
    new Person("PIR000", "Jack Sparrow"), 
    new Person("XYZ987", "Easter Bunny") 
]; 

var people_table = {}; 
for(var i=0; i<people.length; i++){ 
    people_table[ people[i].id ] = people[i]; 
} 

//fast search: 
var someone = people_table['ABC123']; 

po pewnym zapytaniami punktowych zbyt skomplikowane, aby łatwo zrobić ręcznie w JavaScripcie, więc może to być dobry pomysł, aby wysłać przetwarzania po stronie serwera, więc można użyć bardziej odpowiedniego narzędzia, jak w relacyjnej bazie danych .

+0

Fajnie, ale powinny radzić sobie z duplikatami. – RobG

+0

Obsługa duplikatów to rzeczy, które zaczynają robić się denerwujące. Mam nadzieję, że w każdej chwili możesz podać unikalny identyfikator dla każdego. – hugomg

+0

Fajny pomysł. Hashing jest świetny, jeśli masz wiedzę na temat tego, co będziesz indeksować. W tym przypadku nie mogę tego użyć, lubię to. –

1

Jeśli zamierzasz zrobić to bardzo często, możesz utworzyć indeks dla konkretnych właściwości, dzięki czemu przedmioty będą zwracane o wiele szybciej. na przykład Następujące implementuje obiekt pamięci masowej, który dodaje i pobiera obiekty, które są do niego dodawane.

Zachowuje indeks nazw obiektów (jeśli je posiada), dzięki czemu uzyskanie ich jest wydajne.

Będziesz zauważał uderzenie wydajności tylko dla dużej liczby obiektów (powiedzmy ponad 100) i tylko dla osób z indeksem (chociaż możesz utworzyć indeks dla dowolnej liczby obiektów i może mieć bardziej ogólna metoda).

function Storage() { 
    this.store = []; 
    this.nameIndex = {}; 
} 

// Add item to the store, if has name property, add name to name index 
Storage.prototype.addItem = function(item) { 
    var idx = this.nameIndex; 

    // If the item has a name property 
    if (item.hasOwnProperty('name')) { 

    // If already have an item with that name, add index of 
    // this item to indexs of same named items 
    if (idx.hasOwnProperty(item.name)) { 
     idx[item.name].push(this.store.length); 

    // Otherwise, add this item to the index 
    } else { 
     idx[item.name] = [this.store.length]; 


    } 
    } 
    // Add the item to the store 
    this.store.push(item); 
} 

// Returns a possibly empty array of items with matching names 
Storage.prototype.getItemsByName = function(name) { 
    var result = []; 
    var names; 

    if (this.nameIndex.hasOwnProperty(name)) { 
    list = this.nameIndex[name]; 

     for (var i=0, iLen=list.length; i<iLen; i++) { 
     result.push(this.store[list[i]]); 
     } 
    } 
    return result; 
} 

// Generic method for any property and value 
Storage.prototype.getItemsByAttributeValue = function(propName, propValue) { 
    // loop through items, return array of 
    // those with matching property and value 
} 


var store = new Storage(); 

store.addItem({name:'fred',age:'9'}); 

var obj = store.getItemsByName('fred'); 

alert(obj[0].age); // 9 

store.addItem({name:'sally',age:'12'}); 

obj = store.getItemsByName('sally'); 

alert(obj[0].age); //12 
0

Jeśli mam szukać tablicę wielokrotnie, wtedy iteracyjne go raz, w której każdy klawisz dodać jako właściwość obiektu, a następnie spojrzeć na klucz w tym obiekcie. Utrzymuje to cel wszystkich wyszukiwań w O (n) + c. Pamięć jest wydajna, ponieważ obiekt przechowuje odwołania do danych tablicy lub są to prymitywy. Prosto i szybko.

Powiązane problemy