纯javascript中的延迟赋值
在中,我遇到了以下简化问题: 我们从具有值属性的对象数组开始。我们要计算每个值占值总和的百分比,并将其作为属性添加到结构中。要做到这一点,我们需要知道值的总和,但这个总和不是事先计算出来的纯javascript中的延迟赋值,javascript,deferred-execution,Javascript,Deferred Execution,在中,我遇到了以下简化问题: 我们从具有值属性的对象数组开始。我们要计算每个值占值总和的百分比,并将其作为属性添加到结构中。要做到这一点,我们需要知道值的总和,但这个总和不是事先计算出来的 //Original data structure [ { "value" : 123456 }, { "value" : 12146 } ] //Becomes [ { "value" : 123456, "perc" : 0.9104 }, { "val
//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;
}
vari;
var总和=0;
对于(i=0;i
我们是否可以只检查一次数据结构,然后以某种方式告诉我们,百分比表达式应该只在知道整个总和后才进行计算
我主要对解决纯javascript问题的答案感兴趣。也就是说:没有任何库。根据我的评论,如果不在它上面有效地循环两次,我看不到一种方法来实现这一点
getPercent
行更改为:
current.getPercent = function() {
return this["percent"] || (this["percent"] = this["value"] / total);
}
这将确保计算只在第一次运行
编辑
我运行了一些测试(在我通过测试太多的迭代而崩溃chrome之前忘记了保存,但它们非常简单,可以复制)。
我正在
例如,用一个更少的循环实现这一点的方法是写出由所有可能项组成的整个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;
}
var sum=(数据[0]?数据[0]。值:0)+
(数据[1]?数据[1]。值:0)+
(数据[2]?数据[2]。值:0)+
...
(数据[50]?数据[50]。值:0);
对于(i=0;i
这并不是一个真正的解决方案
您可以使用数组的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;
}
var sum=data.reduce(函数(输出,项){
返回输出+item.value;
},0);
对于(i=0;i
您可以使用ES6承诺,但仍在添加大量函数调用
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);
var数据=[
{“值”:123456},
{“值”:12146}
]
var总和=0;
var-rej=null;
var-res=null;
var def=新承诺(函数(解析、拒绝){
rej=拒绝;
res=决心;
});
功能perc(总计){
this.perc=this.value/total;
}
对于(i=0;i
添加语句10834196
±0.44%
最快的
减少
355539
±1.95%
慢67% 承诺
26325
±8.14%
100%慢 对于循环
9640800
±0.45%
慢11%
再看一看问题,使用堆栈最容易再现所需的效果。这里最简单的方法是创建递归函数而不是循环。递归函数将充当一个循环,卸堆可用于设置percentage属性
/**
*addPercentage的Helper函数
*@param arr数据对象数组
*@param索引
*@param sum
*@return{number}和
*/
函数延迟添加百分比(arr、索引、总和){
//出界
如果(索引>=arr.length){
回报金额;
}
//推动堆栈
sum=deferredAddPercentage(arr,index+1,sum+arr[index].value);
//弹出堆栈
arr[index]。百分比=arr[index]。值/和;
回报金额;
}
/**
*将百分比属性添加到每个包含的对象
*@param arr数据对象数组
*/
功能添加百分比(arr){
延迟添加百分比(arr,0,0);
}
// ******
风险值数据=[{
“价值”:10
}, {
“价值”:20
}, {
“价值”:20
}, {
“价值”:50
}];
增加百分比(数据);
控制台日志(数据)代码>带有的解决方案
它将用于计算的函数f
移动到迭代结束时,然后通过链式函数指定单个项目的百分比
var数据=[
{“值”:123456},
{“值”:12146},
];
reduceRight(函数(f,a,i){//reduceRight,i=0位于reduce required的末尾
var t=f;//临时保存以前的值或函数
f=函数{//获取一个以sum为参数的新函数
a、 perc=a.value/s;//使用reduce末尾的sum进行所需的计算
t&&t(s);//测试并调用以sum为参数的旧func
};
f、 s=(t.s | | 0)+a.value;//向sum添加值,并将sum保存在f的属性中
i | | f(f.s);//在最后一次迭代中,使用sum作为参数调用f
return f;//返回函数
}, 0); // 带属性的启动值(未定义/空不起作用)
document.write(''+JSON.stringify(数据,0,4)+'')
此解决方案使用单个循环计算总和,并使用getter在每个元素上放置computedperc
属性:
function add_percentage(arr) {
var sum = 0;
arr.forEach(e => {
sum += e.value;
setTimeout(() => e.perc = e.value / sum);
});
}
直接的延期
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);
function add_percentage(arr) {
var sum = 0;
arr.forEach(e => {
sum += e.value;
Object.defineProperty(e, "perc", {
get: function() { return this.value / sum; }
});
});
}
function add_percentage(arr) {
var sum = 0;
arr.forEach(e => {
sum += e.value;
setTimeout(() => e.perc = e.value / sum);
});
}