#javascript
Вопрос:
Есть ли метод, более быстрый по производительности, чем выполнение этого:
var value = 2432;
if (value >= 20 amp;amp; value <= 31) return true;
else if (value >= 45 amp;amp; value <= 47) return true;
else if (value >= 82 amp;amp; value <= 86) return true;
...
else if (value >= 1052 amp;amp; value <= 1065) return true;
else if (value >= 2400 amp;amp; value <= 2500) return true;
Условные операторы содержат числа, которые не входят в шаблон. Их число достигает 65 000. Кроме того, диапазоны являются переменными и не пересекаются друг с другом. Диапазон хранится в базе данных SQL:
columns: from, to
rows: [21, 59], [92, 280], etc...
Изначально я думал о создании таблицы поиска, содержащей все числа между диапазонами (например, [20, 21, 21, 23, ... 31, -> 45, 46 47]
).
Есть ли лучший способ?
Комментарии:
1. Это зависит. Фиксированы ли диапазоны? Будете ли вы тестировать несколько чисел в одних и тех же диапазонах?
2. Также определите «быстрее». Быстрее кодировать? Более быстрое время выполнения?
3. Итак, расстояние между диапазонами кажется совершенно переменным, и если оно находится в пределах диапазона, вы просто хотите, чтобы они вернулись
true
?4. Я забыл уточнить — диапазоны не фиксированные, а переменные. Если значение находится в пределах диапазона, оно должно возвращать значение true.
5. разные диапазоны не пересекаются друг с другом, это правильное предположение?
Ответ №1:
Так что, если диапазоны уникальны и не пересекаются друг с другом. Самый быстрый способ проверить, я вижу, чтобы быть следующим алго:
- составьте список пар [начало, конец] или просто используйте два отдельных списка для начальных и конечных точек.
- сортируйте их(это можно было бы сделать очень легко на стороне SQL)
- используя двоичный поиск, найдите первое
start
значение, которое больше вашего номера ссылки - предыдущий пункт дает вам только один диапазон, который вы должны сверить со своим справочным номером.
Если сортировка выполняется на стороне БД, то этот алгоритм будет O(logN), что достаточно быстро.
Ответ №2:
Вы могли бы создать массив [start, end]
массивов:
const ranges = [
[20, 31],
[45, 47],
[82, 86],
// …
[1052, 1065],
[2400, 2500]
];
Затем используйте Array.prototype.find
или Array.prototype.some
, чтобы найти диапазон, value
в котором находится a (например let value = 2432;
):
ranges.find(([start, end]) => value >= start amp;amp; value <= end); // Returns `[2400, 2500]`, which is the range the value is in, or
!!ranges.find(([start, end]) => value >= start amp;amp; value <= end); // Returns `true`, since the value is in a range, or
ranges.some(([start, end]) => value >= start amp;amp; value <= end); // Returns `true`, since the value is in a range, or
Комментарии:
1. Мне нравится, как это лаконично. Я, вероятно, мог бы ускорить это, заменив .find также на цикл for.
2. @John Находит залоги в первом матче, так что вы, скорее всего, не увидите никаких улучшений при использовании цикла for.
3. @ShaunH Хотя я тоже использовал функциональный подход в своем ответе, технически OP прав, что функции производят накладные расходы стека, поэтому цикл for был бы более эффективным. Тем не менее, если вы так озабочены производительностью, у вас либо A: есть десятки/сотни миллионов записей, либо B: вероятно, в первую очередь не следует использовать JavaScript.
Ответ №3:
Вы, безусловно, можете уменьшить количество условных операторов, которые вам нужно написать.
Предполагая , что ваши массивы «от-до» поступают с сервера в форме [ [n1, n2], [n3, n4], ... ]
, вы можете перебирать каждый из ваших диапазонов и return
из функции, как только у вас будет совпадение, или возвращать false в противном случае:
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] amp;amp; value <= rangeArr[1]) {
return true;
}
return false;
}
console.log(isValInRange(valueInRange, ranges)); //true
console.log(isValInRange(valueNotInRange, ranges)); //false
Ответ №4:
Если вы можете выполнить запрос в sql и нет пересечения, то просто создайте таблицу со всеми возможными значениями от 1 до 65000 и укажите столбец bool, если число допустимо с индексами. Вы действительно получаете удар только по производительности обновления с точки зрения производительности. В этом случае сделайте:
Value isRange
1 true
ВЫБЕРИТЕ * ИЗ таблицы диапазонов, где Значение = @Значение и isRange = true
Это оптимизирует чтение, однако, если вы часто обновляетесь, это не поможет.
Вы часто обновляетесь?
Ответ №5:
Если вы собираетесь проверять эти значения значительно чаще, чем будете обновлять их, одним из вариантов было бы построить дерево с диапазонами и искать его немного быстрее, чем повторять все варианты. Однако вы захотите сохранить дерево сбалансированным, иначе это не принесет вам большой пользы.
/*
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.<
} else if (value > current.max) {
current = current.>
} else {
return true;
}
}
return false;
}
Это, по сути, делает это для ценности:
- Перейдите на средний диапазон.
- Если текущий узел равен нулю, верните значение false (значение не находится ни в каком диапазоне).
- Если значение находится в текущем диапазоне, верните значение true (значение находится в диапазоне).
- Если значение меньше текущего минимального значения, перейдите в средний диапазон меньше текущего и вернитесь к шагу 2.
- Если значение больше максимального значения тока, перейдите в средний диапазон, превышающий текущий, и вернитесь к шагу 2.