下划线 - 从排序的对象数组中查找

时间:2014-09-21 21:02:28

标签: javascript underscore.js

Underscore提供函数sortBy来排序对象数组。但是,一旦我有这个排序数组,有没有办法使用二进制搜索找到一个元素?函数find没有利用数组排序的事实,而函数indexOf却没有,但它没有提供指定排序键的方法。

  1. 我错过了什么吗?
  2. 是否有其他JS库可以轻松实现?

2 个答案:

答案 0 :(得分:5)

函数_.sortedIndex用于二进制搜索,但比您的目的更为通用。我只是用它来构建一个sortedFind,例如:

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

示例用法:

// 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

答案 1 :(得分:1)

你没有遗漏任何东西。这有点令人惊讶,不是吗?

Google Closure库支持binarySearch内部的功能(我确定还有其他功能):

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

你会像你想象的那样使用它:

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

如果您不想拖入另一个库,则源很短且可用:

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

我在这里剪切并粘贴重要部分,以防链接发生变化 - 请记住将其归功于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;
};