217 lines
5.9 KiB
JavaScript
217 lines
5.9 KiB
JavaScript
/**
|
|
* @module ol/array
|
|
*/
|
|
|
|
/**
|
|
* Performs a binary search on the provided sorted list and returns the index of the item if found. If it can't be found it'll return -1.
|
|
* https://github.com/darkskyapp/binary-search
|
|
*
|
|
* @param {Array<*>} haystack Items to search through.
|
|
* @param {*} needle The item to look for.
|
|
* @param {Function} [comparator] Comparator function.
|
|
* @return {number} The index of the item if found, -1 if not.
|
|
*/
|
|
export function binarySearch(haystack, needle, comparator) {
|
|
let mid, cmp;
|
|
comparator = comparator || numberSafeCompareFunction;
|
|
let low = 0;
|
|
let high = haystack.length;
|
|
let found = false;
|
|
|
|
while (low < high) {
|
|
/* Note that "(low + high) >>> 1" may overflow, and results in a typecast
|
|
* to double (which gives the wrong results). */
|
|
mid = low + ((high - low) >> 1);
|
|
cmp = +comparator(haystack[mid], needle);
|
|
|
|
if (cmp < 0.0) {
|
|
/* Too low. */
|
|
low = mid + 1;
|
|
} else {
|
|
/* Key found or too high */
|
|
high = mid;
|
|
found = !cmp;
|
|
}
|
|
}
|
|
|
|
/* Key not found. */
|
|
return found ? low : ~low;
|
|
}
|
|
|
|
/**
|
|
* Compare function for array sort that is safe for numbers.
|
|
* @param {*} a The first object to be compared.
|
|
* @param {*} b The second object to be compared.
|
|
* @return {number} A negative number, zero, or a positive number as the first
|
|
* argument is less than, equal to, or greater than the second.
|
|
*/
|
|
export function numberSafeCompareFunction(a, b) {
|
|
return a > b ? 1 : a < b ? -1 : 0;
|
|
}
|
|
|
|
/**
|
|
* {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution} can use a function
|
|
* of this type to determine which nearest resolution to use.
|
|
*
|
|
* This function takes a `{number}` representing a value between two array entries,
|
|
* a `{number}` representing the value of the nearest higher entry and
|
|
* a `{number}` representing the value of the nearest lower entry
|
|
* as arguments and returns a `{number}`. If a negative number or zero is returned
|
|
* the lower value will be used, if a positive number is returned the higher value
|
|
* will be used.
|
|
* @typedef {function(number, number, number): number} NearestDirectionFunction
|
|
* @api
|
|
*/
|
|
|
|
/**
|
|
* @param {Array<number>} arr Array in descending order.
|
|
* @param {number} target Target.
|
|
* @param {number|NearestDirectionFunction} direction
|
|
* 0 means return the nearest,
|
|
* > 0 means return the largest nearest,
|
|
* < 0 means return the smallest nearest.
|
|
* @return {number} Index.
|
|
*/
|
|
export function linearFindNearest(arr, target, direction) {
|
|
const n = arr.length;
|
|
if (arr[0] <= target) {
|
|
return 0;
|
|
} else if (target <= arr[n - 1]) {
|
|
return n - 1;
|
|
} else {
|
|
let i;
|
|
if (direction > 0) {
|
|
for (i = 1; i < n; ++i) {
|
|
if (arr[i] < target) {
|
|
return i - 1;
|
|
}
|
|
}
|
|
} else if (direction < 0) {
|
|
for (i = 1; i < n; ++i) {
|
|
if (arr[i] <= target) {
|
|
return i;
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 1; i < n; ++i) {
|
|
if (arr[i] == target) {
|
|
return i;
|
|
} else if (arr[i] < target) {
|
|
if (typeof direction === 'function') {
|
|
if (direction(target, arr[i - 1], arr[i]) > 0) {
|
|
return i - 1;
|
|
} else {
|
|
return i;
|
|
}
|
|
} else if (arr[i - 1] - target < target - arr[i]) {
|
|
return i - 1;
|
|
} else {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return n - 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Array<*>} arr Array.
|
|
* @param {number} begin Begin index.
|
|
* @param {number} end End index.
|
|
*/
|
|
export function reverseSubArray(arr, begin, end) {
|
|
while (begin < end) {
|
|
const tmp = arr[begin];
|
|
arr[begin] = arr[end];
|
|
arr[end] = tmp;
|
|
++begin;
|
|
--end;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Array<VALUE>} arr The array to modify.
|
|
* @param {!Array<VALUE>|VALUE} data The elements or arrays of elements to add to arr.
|
|
* @template VALUE
|
|
*/
|
|
export function extend(arr, data) {
|
|
const extension = Array.isArray(data) ? data : [data];
|
|
const length = extension.length;
|
|
for (let i = 0; i < length; i++) {
|
|
arr[arr.length] = extension[i];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Array<VALUE>} arr The array to modify.
|
|
* @param {VALUE} obj The element to remove.
|
|
* @template VALUE
|
|
* @return {boolean} If the element was removed.
|
|
*/
|
|
export function remove(arr, obj) {
|
|
const i = arr.indexOf(obj);
|
|
const found = i > -1;
|
|
if (found) {
|
|
arr.splice(i, 1);
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/**
|
|
* @param {Array|Uint8ClampedArray} arr1 The first array to compare.
|
|
* @param {Array|Uint8ClampedArray} arr2 The second array to compare.
|
|
* @return {boolean} Whether the two arrays are equal.
|
|
*/
|
|
export function equals(arr1, arr2) {
|
|
const len1 = arr1.length;
|
|
if (len1 !== arr2.length) {
|
|
return false;
|
|
}
|
|
for (let i = 0; i < len1; i++) {
|
|
if (arr1[i] !== arr2[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Sort the passed array such that the relative order of equal elements is preserved.
|
|
* See https://en.wikipedia.org/wiki/Sorting_algorithm#Stability for details.
|
|
* @param {Array<*>} arr The array to sort (modifies original).
|
|
* @param {!function(*, *): number} compareFnc Comparison function.
|
|
* @api
|
|
*/
|
|
export function stableSort(arr, compareFnc) {
|
|
const length = arr.length;
|
|
const tmp = Array(arr.length);
|
|
let i;
|
|
for (i = 0; i < length; i++) {
|
|
tmp[i] = {index: i, value: arr[i]};
|
|
}
|
|
tmp.sort(function (a, b) {
|
|
return compareFnc(a.value, b.value) || a.index - b.index;
|
|
});
|
|
for (i = 0; i < arr.length; i++) {
|
|
arr[i] = tmp[i].value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Array<*>} arr The array to test.
|
|
* @param {Function} [func] Comparison function.
|
|
* @param {boolean} [strict] Strictly sorted (default false).
|
|
* @return {boolean} Return index.
|
|
*/
|
|
export function isSorted(arr, func, strict) {
|
|
const compare = func || numberSafeCompareFunction;
|
|
return arr.every(function (currentVal, index) {
|
|
if (index === 0) {
|
|
return true;
|
|
}
|
|
const res = compare(arr[index - 1], currentVal);
|
|
return !(res > 0 || (strict && res === 0));
|
|
});
|
|
}
|