将数字与范围中的数字列表进行比较的最快方法?

时间:2018-08-15 20:37:43

标签: javascript performance

是否有一种比执行此操作更快的方法:

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;

条件语句包含不在模式中的数字。这个数字高达65,000。同样,范围是可变的并且彼此不相交。范围存储在SQL数据库中:

columns: from, to
rows: [21, 59], [92, 280], etc...

我最初是想创建一个查找表,其中包含范围之间的所有数字(例如[20, 21, 21, 23, ... 31, -> 45, 46 47])。

有更好的方法吗?

5 个答案:

答案 0 :(得分:4)

因此,如果范围是唯一的并且彼此不相交。 我认为下一个算法是最快的检查方法:

  1. 列出[开始,结束]对列表,或仅使用两个分开的列表作为起点和终点。
  2. 对它们进行排序(在SQL方面可以很容易做到)
  3. 使用二进制搜索找出比您的参考号大的第一个start
  4. 上一个项目只提供了一个范围,您应该对照参考编号进行检查。

如果排序是在数据库端进行的,则该算法将是足够快的O(logN)。

答案 1 :(得分:3)

您可以制作一个[start, end]数组的数组:

const ranges = [
    [20, 31],
    [45, 47],
    [82, 86],
    // …
    [1052, 1065],
    [2400, 2500]
  ];

然后使用Array.prototype.findArray.prototype.some查找value所在的范围(例如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

答案 2 :(得分:0)

如果您可以在sql中进行查询并且没有交集,则仅具有一个表,其所有可能的值在1到65000之间,并且如果数字对索引有效,则具有bool列。您只会对更新性能产生重大影响。 在这种情况下,请执行以下操作:

Value isRange
1     true

SELECT * FROM RangeTable,其中Value = @Value和isRange = true

这为阅读进行了优化,但是,如果您经常更新,则无济于事。

您是否经常更新?

答案 3 :(得分:0)

您当然可以减少必须编写的条件语句的数量。

假设您的“从-到”数组以[ [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] && value <= rangeArr[1]) {
            return true;
    }
    return false;
}

console.log(isValInRange(valueInRange, ranges)); //true
console.log(isValInRange(valueNotInRange, ranges)); //false

答案 4 :(得分:0)

如果要比对这些值进行更多地检查,则一种选择是构造具有范围的树,并搜索它比遍历所有选项快一点。不过,您可能希望使树保持平衡,否则不会对您有多大帮助。

/*
  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;
}

这实际上是为值做的:

  1. 转到中间范围。
  2. 如果当前节点为null,则返回false(值不在任何范围内)。
  3. 如果值在当前范围内,则返回true(值在范围内)。
  4. 如果值小于当前最小值,则转到小于当前值的中间范围,然后返回到步骤2。
  5. 如果值大于当前最大值,则转到大于当前值的中间范围,然后返回到步骤2。