|
@ -1352,16 +1352,21 @@ exports.binarySearchCustom = function (orderedItems, searchFunction, field, fiel |
|
|
* @param {{start: number, end: number}} target |
|
|
* @param {{start: number, end: number}} target |
|
|
* @param {String} field |
|
|
* @param {String} field |
|
|
* @param {String} sidePreference 'before' or 'after' |
|
|
* @param {String} sidePreference 'before' or 'after' |
|
|
|
|
|
* @param {function} an optional comparator, returning -1,0,1 for <,==,>. |
|
|
* @returns {number} |
|
|
* @returns {number} |
|
|
* @private |
|
|
* @private |
|
|
*/ |
|
|
*/ |
|
|
exports.binarySearchValue = function (orderedItems, target, field, sidePreference) { |
|
|
|
|
|
|
|
|
exports.binarySearchValue = function (orderedItems, target, field, sidePreference, comparator) { |
|
|
var maxIterations = 10000; |
|
|
var maxIterations = 10000; |
|
|
var iteration = 0; |
|
|
var iteration = 0; |
|
|
var low = 0; |
|
|
var low = 0; |
|
|
var high = orderedItems.length - 1; |
|
|
var high = orderedItems.length - 1; |
|
|
var prevValue, value, nextValue, middle; |
|
|
var prevValue, value, nextValue, middle; |
|
|
|
|
|
|
|
|
|
|
|
var comparator = comparator != undefined ? comparator : function (a, b) { |
|
|
|
|
|
return a == b ? 0 : a < b ? -1 : 1 |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
while (low <= high && iteration < maxIterations) { |
|
|
while (low <= high && iteration < maxIterations) { |
|
|
// get a new guess
|
|
|
// get a new guess
|
|
|
middle = Math.floor(0.5 * (high + low)); |
|
|
middle = Math.floor(0.5 * (high + low)); |
|
@ -1369,17 +1374,17 @@ exports.binarySearchValue = function (orderedItems, target, field, sidePreferenc |
|
|
value = orderedItems[middle][field]; |
|
|
value = orderedItems[middle][field]; |
|
|
nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field]; |
|
|
nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field]; |
|
|
|
|
|
|
|
|
if (value == target) { // we found the target
|
|
|
|
|
|
|
|
|
if (comparator(value, target) == 0) { // we found the target
|
|
|
return middle; |
|
|
return middle; |
|
|
} |
|
|
} |
|
|
else if (prevValue < target && value > target) { // target is in between of the previous and the current
|
|
|
|
|
|
|
|
|
else if (comparator(prevValue, target) < 0 && comparator(value, target) > 0) { // target is in between of the previous and the current
|
|
|
return sidePreference == 'before' ? Math.max(0, middle - 1) : middle; |
|
|
return sidePreference == 'before' ? Math.max(0, middle - 1) : middle; |
|
|
} |
|
|
} |
|
|
else if (value < target && nextValue > target) { // target is in between of the current and the next
|
|
|
|
|
|
|
|
|
else if (comparator(value, target) < 0 && comparator(nextValue, target) > 0) { // target is in between of the current and the next
|
|
|
return sidePreference == 'before' ? middle : Math.min(orderedItems.length - 1, middle + 1); |
|
|
return sidePreference == 'before' ? middle : Math.min(orderedItems.length - 1, middle + 1); |
|
|
} |
|
|
} |
|
|
else { // didnt find the target, we need to change our boundaries.
|
|
|
else { // didnt find the target, we need to change our boundaries.
|
|
|
if (value < target) { // it is too small --> increase low
|
|
|
|
|
|
|
|
|
if (comparator(value, target) < 0) { // it is too small --> increase low
|
|
|
low = middle + 1; |
|
|
low = middle + 1; |
|
|
} |
|
|
} |
|
|
else { // it is too big --> decrease high
|
|
|
else { // it is too big --> decrease high
|
|
|