将计数器保持在reduce功能内

时间:2014-02-18 19:38:14

标签: javascript

我正在尝试编写一个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?

来完成

4 个答案:

答案 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]