Is there a method faster in performance than doing this:
var value = 2432;
if (value >= 20 && value <= 31) return true;
else if (value >= 45 && value <= 47) return true;
else if (value >= 82 && value <= 86) return true;
...
else if (value >= 1052 && value <= 1065) return true;
else if (value >= 2400 && value <= 2500) return true;
The conditional statements contain numbers that aren't in a pattern. The numbers go up to 65,000. Also the ranges are variable and don't intersect each other. The range is stored in a SQL database:
columns: from, to
rows: [21, 59], [92, 280], etc...
I was initially thinking of creating a lookup table containing all the numbers between the ranges (e.g., [20, 21, 21, 23, ... 31, -> 45, 46 47]
).
Is there a better way?
Is there a method faster in performance than doing this:
var value = 2432;
if (value >= 20 && value <= 31) return true;
else if (value >= 45 && value <= 47) return true;
else if (value >= 82 && value <= 86) return true;
...
else if (value >= 1052 && value <= 1065) return true;
else if (value >= 2400 && value <= 2500) return true;
The conditional statements contain numbers that aren't in a pattern. The numbers go up to 65,000. Also the ranges are variable and don't intersect each other. The range is stored in a SQL database:
columns: from, to
rows: [21, 59], [92, 280], etc...
I was initially thinking of creating a lookup table containing all the numbers between the ranges (e.g., [20, 21, 21, 23, ... 31, -> 45, 46 47]
).
Is there a better way?
Share Improve this question edited Aug 15, 2018 at 23:53 Alvaro Castro 8411 gold badge10 silver badges30 bronze badges asked Aug 15, 2018 at 20:37 JohnJohn 975 bronze badges 10- 2 It depends. Are the ranges fixed? Will you be testing multiple numbers in the same ranges? – Pedro A Commented Aug 15, 2018 at 20:40
- 2 Also define "faster". Faster to code? Faster execution time? – mhodges Commented Aug 15, 2018 at 20:43
-
Okay so the distance of the ranges seem totally variable, and if it's in the range you just want them to return
true
? – zfrisch Commented Aug 15, 2018 at 20:43 - I forgot to clarify - the ranges are not fixed but variable. If a value is within the range, it must return true. – John Commented Aug 15, 2018 at 20:43
- 1 different ranges don't intersect with each other, is it correct assumption? – skyboyer Commented Aug 15, 2018 at 20:44
5 Answers
Reset to default 4So if ranges are unique and don't intersect with each other. The fastest way to check I see to be next algo:
- make a list of pairs [start, end] or just use two separated lists for start points and end points.
- sort them(it could be done really easy on SQL side)
- using binary search find out first
start
value that is larger than your reference number - previous item give your just single range you should check against your reference number.
If sorting is done on DB side, then this algo will be O(logN) that is fast enough.
You could make an array of [start, end]
arrays:
const ranges = [
[20, 31],
[45, 47],
[82, 86],
// …
[1052, 1065],
[2400, 2500]
];
Then use Array.prototype.find
or Array.prototype.some
to find a range that a value
is in (e.g. let value = 2432;
):
ranges.find(([start, end]) => value >= start && value <= end); // Returns `[2400, 2500]`, which is the range the value is in, or
!!ranges.find(([start, end]) => value >= start && value <= end); // Returns `true`, since the value is in a range, or
ranges.some(([start, end]) => value >= start && value <= end); // Returns `true`, since the value is in a range, or
You can certainly reduce the number of conditional statements you have to write.
Assuming your "from-to" arrays arrive from the server in the form [ [n1, n2], [n3, n4], ... ]
, you can loop over each of your ranges and return
from the function once you have a match, or return false otherwise:
let ranges = [ [20, 31], [45, 47] ];
let valueInRange = 46;
let valueNotInRange = 33;
function isValInRange(value, rangeArr) {
for(let i = 0; i < rangeArr.length; i++) {
if(value >= rangeArr[0] && value <= rangeArr[1]) {
return true;
}
return false;
}
console.log(isValInRange(valueInRange, ranges)); //true
console.log(isValInRange(valueNotInRange, ranges)); //false
If you can do the query in sql and there is no intersection, then just have a table with all possible values between 1 and 65000 and have a bool column if the number is valid with indices. You only really take a hit on an update performance wise. In this case do:
Value isRange
1 true
SELECT * FROM RangeTable where Value = @Value and isRange = true
This optimizes for reading, however if you update frequently then this will not help.
Are you updating frequently?
If you're going to be checking against these values significantly more than you'll update them, one option would be to construct a tree with the ranges and search it a little faster than iterating through all of the options. You will want to keep the tree balanced, though, or it won't do you much good.
/*
Construct this dynamically
min: range minimum
max: range maximum
lt: node for ranges less than this range
gt: node for ranges greater than this range
I'd probably make a class for this.
*/
const ranges = {
min: 82,
max: 86,
lt: {
min: 45,
max: 47,
lt: {
min: 20,
max: 31
}
},
gt: {
min: 2400,
max: 2500,
lt: {
min: 1052,
max: 1065
}
}
};
function lookup(value) {
let current = ranges;
while (current) {
if (value < current.min) {
current = current.lt;
} else if (value > current.max) {
current = current.gt;
} else {
return true;
}
}
return false;
}
This essentially does this for the value:
- Go to middle range.
- If current node is null, return false (value not in any range).
- If value is in current range, return true (value is in range).
- If value is less than current min, go to middle range less than current and go back to step 2.
- If value is greater than current max, go to middle range greater than current and go back to step 2.