我正在尝试编写一个reduce函数,它为数组中的每个新唯一值分配一个递增的整数,并构建一个将唯一元素映射到递增索引的字典。
我想要的函数使用如下数组:
[3,1,1,2,3,1,5,1,2]
并输出如下所示的地图:
该功能如下所示:
{3: 0, 1: 1, 2: 2, 5: 3}
一种可能的解决方案是使用reduce,但它需要将计数器保持在函数之外:
var i = 0
var func = [3,1,1,2,3,1,5,1,2].reduce(function(a, b) {
if (!(a in b) {
b[a] = i
i++
}
return b
},{})
有没有办法编写这个函数,但不知何故将计数器保留在函数的范围内?显然我可以将所有东西都包装在一个函数中,但有没有办法只用reduce?
来完成答案 0 :(得分:3)
使用闭包将有助于保持代码清洁:
fun=function(){
var i=0;
return function(b, a) {
if (!(a in b)) {
b[a] = i
i++
}
return b;
};
}();
var func = [3,1,1,2,3,1,5,1,2].reduce(fun,{})
所以你在减少时fun
。
答案 1 :(得分:2)
Array.prototype.reduce takes 4 arguments.您可以考虑使用它们,因为其中一个是索引值。因此不需要计数器。
var func = [3,1,1,2,3,1,5,1,2].reduce(function(prev, curr, idx, arr) {
if(!(prev in curr)) curr[prev] = (prev.length > 0) ? prev.length - 1 : 0;
return curr;
});
答案 2 :(得分:0)
您始终可以将i
投掷到对象本身:
[3,1,1,2,3,1,5,1,2].reduce(function(a,b) {
if(a[b]===undefined) a[b] = a.i++; return a},{i:0})
// {1: 1, 2: 2, 3: 0, 5: 3, i: 4}
答案 3 :(得分:0)
答案是肯定的,但它可能比仅使用范围函数更尴尬。基本上,您只需将状态值复合为所需的实际结果和附加状态,然后在完成缩减时提取结果。
var func = [3,1,1,2,3,1,5,1,2].reduce(function(memo, val) {
if (!(val in memo[0])) {
memo[0][val] = memo[1]
memo[1]++
}
return memo
}, [{}, 0])[0]