this question中,我遇到了以下简化问题:

我们从具有value属性的Objects数组开始。我们要为每个值计算它是值总和的百分比,并将其作为属性添加到结构中。为此,我们需要知道值的总和,但是不会预先计算出该总和。

//Original data structure
[
  { "value" : 123456 },
  { "value" : 12146  }
]

//Becomes
[
  {
    "value" : 123456,
    "perc"  : 0.9104
  },
  {
    "value" : 12146 ,
    "perc"  : 0.0896
  }
]

一个简单且可能是最易读的解决方案是两次遍历数据结构。首先我们计算总和,然后计算百分比并将其添加到数据结构中。
var i;
var sum = 0;
for( i = 0; i < data.length; i++ ) {
  sum += data[i].value;
}
for( i = 0; i < data.length; i++ ) {
  data[i].perc = data[i].value / sum;
}

我们是否可以只对数据结构进行一次遍历,并以某种方式告诉百分比表达式仅应在知道总和后才求值?

我主要对解决纯JavaScript的答案感兴趣。即:没有任何库。

最佳答案

一种减少循环的方法是写出由所有可能项目组成的整个sum语句,例如

var sum = (data[0] ? data[0].value : 0) +
          (data[1] ? data[1].value : 0) +
          (data[2] ? data[2].value : 0) +
          ...
          (data[50] ? data[50].value : 0);

for( i = 0; i < data.length; i++ ) {
   data[i].perc = data[i].value / sum;
}
并不是说这实际上是一个真正的解决方案
您可以使用Array的reduce函数,但是在后台仍然是一个循环,并对每个数组元素进行函数调用:
var sum = data.reduce(function(output,item){
   return output+item.value;
},0);
for( i = 0; i < data.length; i++ ) {
  data[i].perc = data[i].value / sum;
}
您可以使用ES6 Promise,但是您仍然在其中添加了一堆函数调用
var data = [
  { "value" : 123456 },
  { "value" : 12146  }
]
var sum = 0;
var rej = null;
var res = null;
var def = new Promise(function(resolve,reject){
    rej = reject;
    res = resolve;
});
function perc(total){
    this.perc = this.value/total;
}

for( i = 0; i < data.length; i++ ) {
  def.then(perc.bind(data[i]));
  sum+=data[i].value;
}
res(sum);
Perf Tests

09-16 11:26