2014-09-21 11 views
6

Podkreślenie służy do sortowania tablicy obiektów za pomocą funkcji sortBy. Jednak gdy już mam tę posortowaną tablicę, czy istnieje sposób na znalezienie elementu za pomocą wyszukiwania binarnego? Funkcja find nie wykorzystuje faktu, że tablica jest sortowana, podczas gdy funkcja działa, ale nie zapewnia sposobu na określenie klucza sortowania.Podkreślenie - Znajdź z posortowanej tablicy obiektów

  1. Czy czegoś brakuje?
  2. Czy istnieje inna biblioteka JS, która pozwala to łatwo?
+2

ciekawy: co robisz, że wyszukiwanie binarne odróżnia tractable i nie do przyjęcia? Jak duża jest twoja tablica i co robisz? –

+0

Wyszukiwanie binarne musi zostać wykonane na posortowanej tablicy. Ponieważ masz wiele obiektów, najprawdopodobniej będziesz potrzebować niestandardowego rozwiązania. –

+0

Sama tablica ma około 1000 elementów, ale muszę znaleźć w niej wiele elementów. Zatem liniowe przeszukiwanie tej tablicy w pętli może nie być bardzo wydajne. – Naresh

Odpowiedz

3

Funkcja _.sortedIndex służy do wyszukiwania binarnego, ale jest nieco bardziej ogólna niż cel. Chciałbym po prostu użyć go do budowy sortedFind, na przykład:

_.sortedFind = function sortedFind(list, item, key) { 
    return (_.isEqual(item, list[_.sortedIndex(list, item, key)])); 
} 

Przykład użycia:

// http://jsfiddle.net/w3hzrehy/ 
_.sortedFind([10, 20, 30, 40, 50], 10); // true 

var stooges = [{name: 'moe', age: 40}, {name: 'curly', age: 60}]; 
_.sortedFind(stooges, {name: 'larry', age: 50}, 'age'); // false 
_.sortedFind(stooges, {name: 'curly', age: 60}, 'age'); // true 
+0

Dzięki. To jest bardzo blisko! Właściwie to chciałem znaleźć indeks, któremu podano wartość. Tak więc '_.sortedFind (pachoges, {nazwa: 'curly'}, 'name');' powinien zwrócić indeks 1. Wierzę, że '_.sortedIndex (pachoges, {imię: 'curly'}, 'name'); 'robi dokładnie to, mimo że nie wysyłam pełnej pozycji. Wszystko, co muszę zrobić, to sprawdzić, czy zwracany indeks rzeczywiście zawiera przedmiot o nazwie "kręcone". Dokumenty podkreślenia nie są bardzo jasne, ale myślę, że tak właśnie powinno działać. Czy możesz potwierdzić? – Naresh

+0

Oto jsfiddle na to, co chcę: http://jsfiddle.net/w3hzrehy/16/ – Naresh

+0

@Naresh Tak wygląda na to, że używasz 'sortedIndex' poprawnie, jeśli zamierzasz ponownie użyć swojej funkcji, możesz chcieć uogólnić dla funkcji opartych na czystej i czystej wartości: http://jsfiddle.net/w3hzrehy/18/ (uwaga musiałem ulepszyć podkreślenie, aby uzyskać dostęp do funkcji _iteratee().) – lossleader

1

Nie brakuje niczego. To trochę zaskakujące, prawda?

Google Closure biblioteka ma funkcje pomocnicze wewnątrz binarySearch (jestem pewien, że są inne):

http://docs.closure-library.googlecode.com/git/namespace_goog_array.html

będzie go używać tak jak chcesz sobie wyobrazić:

var myArray = getPetArray(); 
goog.array.binarySearch(myArray, 'fido', function(pet) { return pet.name; }); 

Jeśli nie chcesz przeciągać kolejnej biblioteki, źródło jest krótkie i dostępne:

http://docs.closure-library.googlecode.com/git/local_closure_goog_array_array.js.source.html#line989

wyciąć i wkleić tutaj ważną rolę w przypadku linki zmiany - Wystarczy pamiętać, aby dać kredyt Google:

goog.array.binarySearch = function(arr, target, opt_compareFn) { 
    return goog.array.binarySearch_(arr, 
    opt_compareFn || goog.array.defaultCompare, false /* isEvaluator */, 
    target); 
}; 

goog.array.binarySearch_ = function(arr, compareFn, isEvaluator, opt_target, 
opt_selfObj) { 
    var left = 0; // inclusive 
    var right = arr.length; // exclusive 
    var found; 
    while (left < right) { 
    var middle = (left + right) >> 1; 
    var compareResult; 
    if (isEvaluator) { 
     compareResult = compareFn.call(opt_selfObj, arr[middle], middle, arr); 
    } else { 
     compareResult = compareFn(opt_target, arr[middle]); 
    } 
    if (compareResult > 0) { 
     left = middle + 1; 
    } else { 
     right = middle; 
     // We are looking for the lowest index so we can't return immediately. 
     found = !compareResult; 
    } 
    } 
    // left is the index if found, or the insertion point otherwise. 
    // ~left is a shorthand for -left - 1. 
    return found ? left : ~left; 
}; 

goog.array.defaultCompare = function(a, b) { 
    return a > b ? 1 : a < b ? -1 : 0; 
}; 
+0

Dzięki, to jest świetne rozwiązanie. Jednak rozwiązanie @ lossleader'a można było wdrożyć przy bardzo niewielkim dodatkowym wysiłku przy użyciu podkreślenia, dlatego oznaczyłem to jako akceptowaną odpowiedź. Jeszcze raz dziękuję za pomoc. – Naresh