1 | export function minMax (arr) {
|
2 | var len = arr.length
|
3 | var min = Infinity
|
4 | var max = -Infinity
|
5 | while (len--) {
|
6 | var el = arr[len]
|
7 | if (el == null) {
|
8 | // do nothing
|
9 | } else if (el < min) {
|
10 | min = el
|
11 | } else if (el > max) {
|
12 | max = el
|
13 | }
|
14 | }
|
15 | if (min === Infinity) {
|
16 | min = max
|
17 | } else if (max === -Infinity) {
|
18 | max = min
|
19 | }
|
20 | if (min === Infinity || min === -Infinity) {
|
21 | // all values were null
|
22 | min = null
|
23 | max = null
|
24 | }
|
25 | return [min, max]
|
26 | }
|
27 |
|
28 | /**
|
29 | * Return the indices of the two neighbors in the sorted array closest to the given number.
|
30 | *
|
31 | * @example
|
32 | * var a = [2,5,8,12,13]
|
33 | * var i = CovUtils.indicesOfNearest(a, 6)
|
34 | * // i == [1,2]
|
35 | * var j = CovUtils.indicesOfNearest(a, 5)
|
36 | * // j == [1,1]
|
37 | * var k = CovUtils.indicesOfNearest(a, 50)
|
38 | * // k == [4,4]
|
39 | *
|
40 | * @param {Array<number>} a The array to search through. Must be sorted, ascending or descending.
|
41 | * @param {number} x The target number.
|
42 | * @return {[lo,hi]} The indices of the two closest values, may be equal.
|
43 | * If `x` exists in the array, both neighbors point to `x`.
|
44 | * If `x` is lower (greater if descending) than the first value, both neighbors point to 0.
|
45 | * If `x` is greater (lower if descending) than the last value, both neighbors point to the last index.
|
46 | */
|
47 | export function indicesOfNearest (a, x) {
|
48 | if (a.length === 0) {
|
49 | throw new Error('Array must have at least one element')
|
50 | }
|
51 | var lo = -1
|
52 | var hi = a.length
|
53 | const ascending = a.length === 1 || a[0] < a[1]
|
54 | // we have two separate code paths to help the runtime optimize the loop
|
55 | if (ascending) {
|
56 | while (hi - lo > 1) {
|
57 | let mid = Math.round((lo + hi) / 2)
|
58 | if (a[mid] <= x) {
|
59 | lo = mid
|
60 | } else {
|
61 | hi = mid
|
62 | }
|
63 | }
|
64 | } else {
|
65 | while (hi - lo > 1) {
|
66 | let mid = Math.round((lo + hi) / 2)
|
67 | if (a[mid] >= x) { // here's the difference
|
68 | lo = mid
|
69 | } else {
|
70 | hi = mid
|
71 | }
|
72 | }
|
73 | }
|
74 | if (a[lo] === x) hi = lo
|
75 | if (lo === -1) lo = hi
|
76 | if (hi === a.length) hi = lo
|
77 | return [lo, hi]
|
78 | }
|
79 |
|
80 | /**
|
81 | * Return the index of the value closest to the given number in a sorted array.
|
82 | *
|
83 | * @example
|
84 | * var a = [2,5,8,12,13]
|
85 | * var i = CovUtils.indexOfNearest(a, 6)
|
86 | * // i == 1
|
87 | * var j = CovUtils.indexOfNearest(a, 7)
|
88 | * // j == 2
|
89 | * var k = CovUtils.indexOfNearest(a, 50)
|
90 | * // k == 4
|
91 | *
|
92 | * @param {Array<number>} a The array to search through. Must be sorted, ascending or descending.
|
93 | * @param {number} x The target number.
|
94 | * @return {number} The array index whose value is closest to `x`.
|
95 | * If `x` happens to be exactly between two values, then the lower index is returned.
|
96 | */
|
97 | export function indexOfNearest (a, x) {
|
98 | var i = indicesOfNearest(a, x)
|
99 | var lo = i[0]
|
100 | var hi = i[1]
|
101 | if (Math.abs(x - a[lo]) <= Math.abs(x - a[hi])) {
|
102 | return lo
|
103 | } else {
|
104 | return hi
|
105 | }
|
106 | }
|