如何在某些范围内映射数字

时间:2019-06-11 07:03:50

标签: javascript normalize

我有一个范围,例如[0, 100] = [minValue, maxValue],范围数,例如BANDS_NUMBER = 5。 所以我可以获得这些乐队:

[0 - 20]
[21 - 40]
[41 - 60]
[61 - 80]
[81 - 100]

然后我要在每个范围内关联一个比例值

i: 0   -->  [0 - 20]   -->  0.2
i: 1   -->  [21 - 40]  -->  0.4
i: 2   -->  [41 - 60]  -->  0.6
i: 3   -->  [61 - 80]  -->  0.8
i: 4   -->  [81 - 100] -->  1

此值的计算方法如下:(i + 1) / BANDS_NUMBER,其中i是假设循环的索引。

然后我有一个输入n,其值在[minValue, maxValue] = [0, 100]范围内。

我想要的是与此数字相关的比例值。 因此,例如,如果:

n = 0  --> scaleValue = 0.2 
n = 10 --> scaleValue = 0.2 
n = 20 --> scaleValue = 0.2 
n = 35 --> scaleValue = 0.4
n = 68 --> scaleValue = 0.8 
n = 99 --> scaleValue = 1
...

如何创建类似的函数?我想像这样的功能:

function map(n, minValue, maxValue, bandsNumber) {
  const scaleValue = ...
  return scaleValue
}

这里的所有值都是示例,我希望它们都可以与其他任何值一起使用。

我不知道该怎么做。我需要一些帮助...

3 个答案:

答案 0 :(得分:2)

您可以采用一个公式,该公式可以获取范围和位置并返回归一化的值。

由于范围太长(最后一个值包含在间隔中),您需要检查最后一个值并防止在所需间隔之外获取下一个值。

function normalize(min, max, bands, n) {
    return n === max
        ? 1
        : Math.floor(1 + ((n - min) / (max - min)) * bands) / bands;
}

// 0.2 0.2 0.4 0.4 0.8 1 1
console.log(...[0, 10, 20, 35, 68, 99, 100].map(normalize.bind(null, 0, 100, 5)));

答案 1 :(得分:2)

尼娜·舒尔茨(Nina Scholz)的answer是错误的。她的规范化函数针对值0.4返回0.2而不是20

function normalize(min, max, bands, n) {
    return n === max
        ? 1
        : Math.floor(1 + ((n - min) / (max - min)) * bands) / bands;
}

console.log(normalize(0, 100, 5, 20)); // expected 0.2, actual 0.4

由于20在第一个频段中,因此其值应为0.2

i: 0   -->  [0  - 20]  -->  0.2
i: 1   -->  [21 - 40]  -->  0.4
i: 2   -->  [41 - 60]  -->  0.6
i: 3   -->  [61 - 80]  -->  0.8
i: 4   -->  [81 - 100] -->  1

正确的答案是:

const index = (min, max, bands, n) =>
    Math.floor(bands * (n - min) / (max - min + 1));

const band = n => index(0, 100, 5, n);

console.log(band(0),  band(20));  // 0 0
console.log(band(21), band(40));  // 1 1
console.log(band(41), band(60));  // 2 2
console.log(band(61), band(80));  // 3 3
console.log(band(81), band(100)); // 4 4

如您所见,边缘案例被正确处理。我们如何得到这个答案?

  1. 首先,我们找到范围的长度为max - min + 1+ 1之所以重要,是因为[0 - 100]范围内包含101个元素。
  2. 接下来,我们获得给定范围内的数字n的索引(即n - min)。
  3. 然后,我们将n的索引除以该范围内的元素数,以获得[0 - 1)范围内的值。请注意,1不在范围内。
  4. 最后,我们将该值乘以带数,然后舍弃小数部分。结果就是我们的索引。

请注意,如果范围的长度不能被波段数整除,则前x个波段将有一个附加元素,其中x是划分范围长度的余数乐队的数量。

最后,我们可以通过增加结果索引然后将其除以频段数来获得所需的值:

const index = (min, max, bands, n) =>
    Math.floor(bands * (n - min) / (max - min + 1));

const value = (min, max, bands, n) =>
    (index(min, max, bands, n) + 1) / bands;

const result = n => value(0, 100, 5, n);

console.log(result(0),  result(20));  // 0.2 0.2
console.log(result(21), result(40));  // 0.4 0.4
console.log(result(41), result(60));  // 0.6 0.6
console.log(result(61), result(80));  // 0.8 0.8
console.log(result(81), result(100)); // 1 1

希望有帮助。

答案 2 :(得分:1)

您可以使用本机Array.map函数来映射每个值。

类似这样的东西:

const vals = [
  [0, 20],
  [21, 40],
  [41, 60],
  [61, 80],
  [81, 100],
];

const BANDS_NUMBER = 5;

const result = vals.map((range, index) => (index + 1) / BANDS_NUMBER);

console.log(result);