如何在JavaScript中对一组正数进行归一化处理?

9

我有一个填充了正整数值的数组,如何将此列表归一化,使最大值始终为100?谢谢!


4
你尝试过什么?(翻译的是一个网站链接,链接内容为程序员在遇到问题时常被问及的问题) - ruakh
请更具体地说明。您要对这些值做什么?是乘以它们还是去除它们? 您想要一个百分比还是一个比率? - tonino.j
2
你需要更具体一些。如果你正在对值进行归一化,使最大值缩小到恰好等于100,那么将该比例应用于所有其他数字将不会使它们保持为整数。所以你是想让最高的数字缩放到恰好100,即使你随后得到浮点数,还是想要丢弃高于100的数字(过滤),或者将所有大于100的数字夹紧等于100,并保持其余数字不变(扭曲比例),还是想做其他事情? - Norguard
7个回答

32

这个想法是首先找出数组中最大的数字(使用applyMath.max方法),然后计算该最大数字与100之间的比例。

接下来,只需要通过循环遍历你的数组并将所有数字除以该比例:

var numbers = [3, 8, 45, 74, 123],
    ratio = Math.max.apply(Math, numbers) / 100,
    l = numbers.length,
    i;

for (i = 0; i < l; i++) {
    numbers[i] = Math.round(numbers[i] / ratio);
}

这是示例代码:http://jsfiddle.net/XpRR8/


注意: 我使用Math.round函数将数字四舍五入到最近的整数。如果你希望保留小数,只需删除该函数调用即可。

for ( i = 0; i < l; i++ ) {
    numbers[i] /= ratio;
}

这里是示例链接:http://jsfiddle.net/XpRR8/1/


如果您不需要支持IE8及以下版本,则可以使用Array.prototype.map()

var numbers = [3, 8, 45, 74, 123],
    ratio = Math.max.apply(Math, numbers) / 100;

numbers = numbers.map(function (v) {
    return Math.round(v / ratio);
});

这里是代码片段:http://jsfiddle.net/XpRR8/2/


如果你支持IE8,但仍在使用jQuery,可以使用$.map()代替:

numbers = $.map(numbers, function (v) {
    return Math.round(v / ratio);
});

这是代码片段:http://jsfiddle.net/XpRR8/3/


更新:如下方评论中@wvxvw所指出的,如果你担心某些边缘实现对apply处理参数数目有人为限制,那么你可以使用循环代替Math.max.apply。以下是一个例子(假设既不存在Array.prototype.map,也不存在$.map):

var numbers = [3, 8, 45, 74, 123],
    ratio = 0,
    i = numbers.length;

while (i--) numbers[i] > ratio && (ratio = numbers[i]);

ratio /= 100;
i = numbers.length;

while (i--) numbers[i] = Math.round(numbers[i] / ratio);

这里有一个示例代码:http://jsfiddle.net/XpRR8/4/


如果你正在使用ES6,这将变得非常简单:

var numbers = [3, 8, 45, 74, 123];
var ratio = Math.max(...numbers) / 100;

numbers = numbers.map(v => Math.round(v / ratio));

@wvxvw - 有趣。这里是使用apply测试10,000个元素的示例,在所有主流浏览器中都能完美运行;我甚至在5个最新的IE浏览器(6-10)中进行了测试。由于性能差异似乎倾向于apply(在IE < 9中差异非常大),我建议坚持使用apply。(顺便说一句:Firefox似乎正在使用一些疯狂的巫术来实现循环方法的异常性能。不解释)。 - Joseph Silber
@wvxvw - 虽然你说得没错,我的循环实现并不是最有效的,但使用你的循环也没有改变情况太多:旧版本的IE(可以说这些优化最需要的地方)仍然明显更喜欢apply - Joseph Silber
@wvxvw - 你的普通循环代码是错误的。它无法找到max数字;它总是返回array[array.length - 1]。我已经创建了第三个版本的测试,结果类似。 - Joseph Silber

4

像这样

function Normalize(array, value)
{ 
 for( var i = 0, len = array.length; i < len; i++ )
 {
  if( parseInt(array[i]) > value) array[i] = value;
 }
}

然后使用它:

var arr = [];
arr.push(101);
arr.push(5);
arr.push(6);
Normalize(arr,100);

2
我尊重你想要帮忙,但你刚刚替别人完成了他们的工作。:[ 就记录而言,我不是那个-1。 - Snuffleupagus
@Snuffleupagus - 还有其他回答呢? - Travis J
2
我认为 var arr = [101, 5, 6] 更简单易读...只是这么说。 - Derek 朕會功夫
@Derek - 我认为也是,但我试图让它感觉好像不同的地方附加到数组中。 - Travis J

1
function normalize(arr, max) {
    // find the max value
    var m = 0;
    for(var x=0; x<arr.length; x++) m = Math.max(m, arr[x]);
    // find the ratio
    var r = max / m;
    // normalize the array
    for(var x=0; x<arr.length; x++) arr[x] = arr[x] * r;
    return arr;
}

1
将您的数组传递到以下 函数 中:

function normalize_array(arr) {

  normalize = function(val, max, min) { 
    return(val - min) / (max - min); 
  }

  max = Math.max.apply(null, arr) 
  min = Math.min.apply(null, arr)

  hold_normed_values=[]
  arr.forEach(function(this_num) {
    hold_normed_values.push(normalize(this_num, max, min))
  })

  return(hold_normed_values)

}

例子:

nums = [10, 20, 30, 40, 50]

使用方法:

normalize_array(mums)

enter image description here


0

对LastCoder的代码进行编辑,以支持负数

function normalize(arr, max) {
    // find the max value
    var max = arr[0];
    var min = arr[0];
    for(var x=0; x<arr.length; x++) 
        max = Math.max(m, arr[x];
    for(var x=0; x<arr.length; x++) 
        min = Math.min(m, arr[x];

    // normalize the array
    for(var x=0; x<arr.length; x++) 
        arr[x] = (arr[x] - min) / (max - min);

    return arr;
}

0

你可以使用 Math.max.apply(arr) 获取最大值,然后通过循环或使用 arr.map 将所有数字乘以 100/max。完成。


0
你需要找到最大值并将所有数字缩放到目标范围。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接