This repository was archived by the owner on Nov 3, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Copy pathbinary_search.js
124 lines (110 loc) · 3 KB
/
binary_search.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
'use strict';
/* exported utils */
var utils = window.utils || {};
/**
* This function performs a binary search over an already sorted array
* target is the target item to search for
* array is the sorted array
* options is an optional object which may contain
* the start and end position (from, to)
* an optional arrayField which indicates the object property that contains the
* comparable item and transform and compare functions
*
* Returns an array with the positions on which the target item was found
*
*/
utils.binarySearch = function(target, array, options) {
var arrayField = options.arrayField,
transformFunction = options.transformFunction,
compareFunction = options.compareFunction;
// Obtains the comparable item by transforming if necessary
function getItem(array, index) {
var item = array[index];
if (arrayField) {
item = item[arrayField];
if (typeof transformFunction === 'function') {
item = transformFunction(item);
}
}
return item;
}
// Compares the target with an array item
function compare(target, item) {
var out;
if (typeof compareFunction === 'function') {
out = compareFunction(target, item);
}
else {
if (typeof target === 'string') {
out = target.localeCompare(item);
}
else {
out = target.toString().localeCompare(item);
}
}
return out;
}
var from = options.from;
if (typeof from === 'undefined') {
from = 0;
}
var to = options.to;
if (typeof to === 'undefined') {
to = array.length - 1;
}
if (to < from) {
// Not found
return [];
}
var middleIndex = Math.floor((to - from) / 2);
var item = getItem(array, from + middleIndex);
var compareResult = compare(target, item);
if (compareResult === 0) {
// Once a result is found let's iterate in both directions to get the rest
// Just in case there are more than one result
var results = [from + middleIndex];
var next = from + middleIndex + 1;
var finish = false;
while (next <= (array.length - 1) && !finish) {
item = getItem(array, next);
if (compare(target, item) === 0) {
results.push(next);
}
else {
finish = true;
}
next++;
}
finish = false;
next = from + middleIndex - 1;
while (next >= 0 && !finish) {
item = getItem(array, next);
if (compare(target, item) === 0) {
results.push(next);
}
else {
finish = true;
}
next--;
}
return results;
}
else if (compareResult < 0) {
return utils.binarySearch(target, array, {
from: from,
to: to - middleIndex - 1,
arrayField: arrayField,
transformFunction: transformFunction,
compareFunction: compareFunction
});
}
else {
return utils.binarySearch(target, array, {
from: from + middleIndex + 1,
to: to,
arrayField: arrayField,
transformFunction: transformFunction,
compareFunction: compareFunction
});
}
};