创建一个映射回调,按数组和缩放每个数组值
Create a map callback to scale each array value by array sum
我的目标是写一个回调函数…
function proportionize(val,ind,arr){
...
}
这样当提供给Array.prototype时。映射时,返回数组中的每个值各自占数组总数的比例。
例如,let myArray = [1,2,3] // Sums to 6
let proportions = myArray.map( proportionalize ) // [1/6, 2/6, 3/6]
我希望这是…
- 自包含 -我不想提前计算总和
- 有效率 -我不想在每次迭代时重新计算总和
- 可与其他fn的互换-参见下面的编辑
这个问题很简单没有这些条件。即使有了这3个标准,我仍然觉得有一些简单/明显的方法可以做到这一点(也许是尝试在每次迭代中共同的闭包中"保存"总和),但出于某种原因,我还是一片空白。什么好主意吗?
测试工作回答…
let arr = [1,2,3],
callbacks = [Math.sqrt, Math.round, Math.sin, **proportionalize**, etc...];
for(cb in callbacks){
console.log(arr.map(callbacks[cb]))
}
编辑
还有,作为参考,有一个非回答"工作",但我会考虑一个非回答,因为它需要传递一个参数给一个函数,然后生成回调。我希望对map的调用与对任何其他函数的调用相匹配。例如…
// The "working" non-answer
function proportionalize(arrIn){
let total = arrIn.reduce( (a,b)=>a+b);
return (val,ind,arr)=>{ return val/total };
}
myArray.map(proportionalize(myArray)) // works but I'd have to call differently than...
myArray.map(Math.sqrt)
这个答案是有效的,但是有一些我不喜欢的地方…
方法:
- 只计算第一次迭代的总数
- 将总数"保存"到数组,
arr.total
(每次迭代都可用) - 在地图迭代中使用
arr.total
- 在返回数组之前删除最后一次迭代的
total
属性
代码:
function proportionalize(val, ind, arr){
if(ind===0){
arr.total = arr.reduce( (a,b)=>a+b);
}
let proportion = val/arr.total;
if(ind===(arr.length-1)){
delete arr.total;
}
return proportion;
}
[1,2,3].map(proportionalize) // [ 0.16666666666666666, 0.3333333333333333, 0.5 ]
我不喜欢的:
我正在修改数组,添加和删除"total"属性。一般来说,我不想假设属性没有被用于其他用途。该属性名称可以更改为随机的字母字符串或其他东西,但这仍然感觉有点粗糙。
请记住,[1,2,3].map(proportionalize)
将proportionalize
应用于数组的每个元素。这不是对数组本身的操作,而是对数组元素的操作。
虽然这不是一个"map回调",你现有的解决方案可以包装如下:
Array.prototype.proportionalize = function() {
let sum = this.reduce((a,b) => a+b);
return this.map(x => x/sum);
}
例如:> [1,2,3].proportionalize()
[ 0.16666666666666666, 0.3333333333333333, 0.5 ]
这个问题可以更一般地问…
当我用给定的回调函数调用map时,我如何在每个回调函数的实例/调用之间创建/利用共享状态?一旦这个问题得到了答案,你就可以使用短路计算之类的方法来防止不必要的重复计算。
我想到Array.prototype.map已经通过可选的thisArg
提供了此功能。如果this
还没有被使用,提供一个空对象{}
,允许回调调用修改/共享相同的this
,而不修改在map调用生命周期之外持续存在的状态。
从这个空状态开始,让我们只计算未计算过的总数,并且每次迭代都可以访问总数。
proportionalize = function(val, ind, arr){
this.total = this.total || arr.reduce((x,y)=>x+y);
return val/this.total;
}
let arr = [1,2,3],
callbacks = [Math.round, proportionalize];
for(cb in callbacks){
console.log(arr.map(callbacks[cb],{}))
// => [1,2,3], [ 0.16666666666666666, 0.3333333333333333, 0.5 ]
}
arr = [1,2,7];
for(cb in callbacks){
console.log(arr.map(callbacks[cb],{}))
// => [1,2,3], [ 0.1, 0.2, 0.7 ]
}
- 正在尝试将JSON文件放入JS数组
- 如何获取文本框组的值,并使用jquery将它们放入(key:Value)数组中
- ajax成功地将数组中的数据放入表中各自的输入中
- 如何在javascript中循环并将JSON对象放入数组中
- 在Codrops的内容中添加数组元素展开缩略图网格预览
- 将数组放入以下格式的名称:url
- 根据条件将函数放入数组中(如果选中复选框)
- 按值名称过滤掉重复的对象,并将其放入新数组中
- 如何将数组值放入动画中
- 为什么我需要在JavaScript的数组里放空格
- 如何将一个对象(associative数组)放入一个对象中(associativearray)
- 递归地将数组元素放入它们自己的数组中
- 如何在保持最小值的同时缩放值数组?
- 如何获得绝对坐标(相对于画布)后,在织物组缩放js
- 创建一个映射回调,按数组和缩放每个数组值
- 如何使用Math对象按数组的长度进行缩放
- 缩放容器的Jquery可拖动容器数组值
- 如何将SAFEARRAY(字节数组)放入HTML隐藏字段
- 开放图层 3:缩放地图到数组中的坐标
- 高图缩放和x轴与字符串数组的类别