最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascriptlodash binary search by function - Stack Overflow

programmeradmin1浏览0评论

For most such operations, we're using the lodash library. I'm open to other suggestions, but would likely just write the function myself before importing a new lib.

lodash has sortedIndexOf, which performs a binary search in a sorted array (returns index of match or -1 if not found). It also has sortedIndexBy, which, using a binary search, finds the index to insert a new element where you can specify a function to use to do the sort parison (returns a valid index if not found)

I cannot find a function to do a find (return index only if found) using an efficient sorted search allowing you to specify the sort value function. It might look something like this:

_.sortedFindBy(array, value, function(x){x.timestamp})

I believe I could use

var idx = _.sortedIndexBy(array, value, function(x){x.timestamp})
return (array[idx] && array[idx].timestamp === value.timestamp) ? idx : -1

but it just seems odd to me to not have the syntactically more pact and intuitive form of an already feature-rich set of sorted search functions.

Am I missing something from the lodash docs? Is there a built in way to do this more idiomatically? Or should I go with my extra-check method?

For most such operations, we're using the lodash library. I'm open to other suggestions, but would likely just write the function myself before importing a new lib.

lodash has sortedIndexOf, which performs a binary search in a sorted array (returns index of match or -1 if not found). It also has sortedIndexBy, which, using a binary search, finds the index to insert a new element where you can specify a function to use to do the sort parison (returns a valid index if not found)

I cannot find a function to do a find (return index only if found) using an efficient sorted search allowing you to specify the sort value function. It might look something like this:

_.sortedFindBy(array, value, function(x){x.timestamp})

I believe I could use

var idx = _.sortedIndexBy(array, value, function(x){x.timestamp})
return (array[idx] && array[idx].timestamp === value.timestamp) ? idx : -1

but it just seems odd to me to not have the syntactically more pact and intuitive form of an already feature-rich set of sorted search functions.

Am I missing something from the lodash docs? Is there a built in way to do this more idiomatically? Or should I go with my extra-check method?

Share Improve this question edited Jun 8, 2016 at 20:34 Andrew Schwartz asked Jun 8, 2016 at 19:51 Andrew SchwartzAndrew Schwartz 4,6573 gold badges28 silver badges61 bronze badges 1
  • 1 I don't think you're missing anything from the docs, and there isn't an idiomatic way that I could find that was more efficient than what you wrote. – DevShep Commented Jun 9, 2016 at 0:41
Add a ment  | 

3 Answers 3

Reset to default 7

Reading through lodash code, looks like it has a pair of functions to search for a minimum index to insert an element while keeping array sorted - sortedIndex and sortedIndexBy. Former takes an array and a value, latter also accepts iteratee - a function, that is invoked for each element. Note, there are also sortedLastIndex and sortedLastIndexBy. Those look for the last index at which to insert a value.

When it es to checking whether element is in the array and returning its index when it is, there's no function that accepts an iteratee, just a lonely sortedIndexOf. It would be only logical to have sortedIndexOfBy (the naming starts to get tricky here), to accept an iteratee, as well as sortedLastIndexOfBy.

I like your idea of naming it sortedFindBy and will try to implement it along with sortedLastFindBy and add a pull request to lodash.

Your extra-check solution is perfectly fine for now and takes advantage of the binary search optimization while not adding too much of extra code.

In the future, when sortedFindBy is included in lodash, you can always swap your code for the new function call.

_.sortedFindBy(array, value, function(x){x.timestamp})

You won't see any difference in performance of your code, however.

I gave some thought on this. I don't use neither lodash nor underscore but the following pure JS code might serve your purposes. It does a binary search on sorted items of primitives or objects. A provided callback is used to retrieve the value of the object property that the array's sorting is based upon. If the callback is not provided it will default to x => x (function(x) {return x}) and it will assume the array items are primitive type. At the moment this will do only numerical parisons but a parison callback can also be added.

Array.prototype.sortedFindIndex = function(val, cb = x => x) { // default callback for primitive arrays
  var deli = this.length-1,                                    // delta index
      base = 0;                                                // base to add the delta index
  while (deli > 0 && cb(this[base + deli]) != val) {
  	deli = ~~(deli/2);
  	cb(this[base + deli]) < val && (base += deli);
  }
  return cb(this[base + deli]) === val ? base + deli : -1;
};
var ara = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],
    ina = ara.sortedFindIndex(17),
    arb = [{a:0,b:"foo"},{a:1,b:"bar"},{a:2,b:"baz"},{a:3,b:"qux"},{a:4,b:"fox"},{a:5,b:"pun"},{a:6,b:"alf"}],
    inb = arb.sortedFindIndex(4, o => o.a);
console.log(ina);
console.log(inb);

You can play with and modify it here

The value parameter in the call to sortedIndexBy should have a timestamp property.

From this line:

var idx = _.sortedIndexBy(array, value, function(x){x.timestamp})

Replace value by { timestamp: value}

var idx = _.sortedIndexBy(array, { timestamp: value} , function(x){x.timestamp})
发布评论

评论列表(0)

  1. 暂无评论