Javascript减少功能

时间:2016-11-07 12:33:51

标签: javascript arrays

您好我有一个数组如下:

[[1,1],[2,8],[3,12],[4,13],[5,23],[6,30],[7,41],[8,44],[9,50]]

所以我们说它是[[x,y]]

的格式

正如你可以看到上面的数组,内部数组中的第一个元素来自1,2...6 x ,内部数组的第二个元素是1,8,12,13,23 and 30,这是的ý即可。 这是一个 y 的累积数组,我想将其转换为非累积但有一定的扭曲。

我希望将 y 转换为非累积数组,方法是在 x <的最后第3个值与 y 的值之间取得差异/ p>

因此,我希望最终结果如下:

[[1,1],[2,8],[3,0],[4,1],[5,11],[6,0],[7,11],[8,14],[9,0]]

我在这里试过一个小提琴: https://jsfiddle.net/gxytx6ka/1/

到目前为止,我已经能够通过Dekel(stackoverflow guy)的帮助得到两个数组元素之间的区别,正如你在上面的小提琴中看到的那样:

$(document).ready(function() {
  var old_arr = [ [1, 1], [2, 8], [3, 12], [4, 13], [5, 23], [6, 30], [7, 41], [8, 44], [9, 50] ];
  var new_arr = old_arr.reduce(function(a, b, c, d) {
    if (a.length) {
      a.push([d[c][0], d[c][1] - d[c - 1][1]])
    } else {
      a = [b]
    }
    return a;
  }, []);

  console.log(new_arr);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

输出:

[[1,1],[2,7],[3,4],[4,1],[5,10],[6,7],[7,11],[8,3],[9,6]]

但我想:

[[1,1],[2,8],[3,0],[4,1],[5,11],[6,0],[7,11],[8,14],[9,0]]

我无法得到。

我尝试在if条件下使用a%3==0,但没有工作...... 基本上我想以有效的方式获得最终输出。

4 个答案:

答案 0 :(得分:8)

为什么reduce?一个简单的循环可以完美地完成工作:

let a = [[1,1],[2,8],[3,12],[4,13],[5,23],[6,30],[7,41],[8,44],[9,50]];

let out = [],
    n = 0,
    lastY = 0;

for (let [x, y] of a) {
    if (++n % 3 == 0)
        lastY = y;
    out.push([x, y - lastY]);
}

console.log(JSON.stringify(out))

答案 1 :(得分:3)

您可以使用Array#map,它只返回一个包含结果的数组。

&#13;
&#13;
var array = [[1,1], [2,8], [3,12], [4,13], [5,23], [6,30], [7,41], [8,44], [9,50]],
    result = array.map(function (a, i) {
        (i + 1) % 3 || (this.last = a[1]);
        return [a[0], a[1] - this.last];
    }, { last: 0 });

console.log(result);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

ES6

&#13;
&#13;
var array = [[1,1], [2,8], [3,12], [4,13], [5,23], [6,30], [7,41], [8,44], [9,50]],
    result = array.map((l => ([x, y], i) => (++i % 3 || (l = y), [x, y - l]))(0));

console.log(result);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;

答案 2 :(得分:1)

使用reduce,你可以这样做(也使用ES6箭头功能和传播操作符):

&#13;
&#13;
var arr = [[1,1], [2,8], [3,12], [4,13], [5,23], [6,30], [7,41], [8,44], [9,50]];

var result = arr.reduce( ([arr, v], [x, y], i) =>
      [[...arr,[x, i%3==2 ? 0 : y-v]], i%3==2 ? y : v], [[],0])[0];

console.log(result);
&#13;
&#13;
&#13;

解释

使用双初始值(一对)调用

reduce

[[],0]

第一个元素是将累积到最终结果中的数组,第二个元素是后续y值将被偏移的当前值。

这两个值由参数[arr, v]捕获,这是一个解构赋值(ES6)。 reduce回调将始终返回一个新的对,具有扩展arr和(可能)更新v

回调函数还从原始数组中获取当前[x, y]对。这也是一个解构分配,因此您可以直接访问xy个变量。第三个参数i是原始数组中当前的从零开始的索引。

如上所述,回调返回一对。该对中的第一个元素构造如下:

[...arr, [x, i%3==2 ? 0 : y-v]]

...arr表示法将以前收集的结果元素作为列表进行传播,并将一对添加到该列表中:[x, i%3==2 ? 0 : y-v]x只是从原始[x, y]复制,但是y跟随三元运算符所请求的逻辑:如果我们在一个索引,当除以3时,余数为2 ,那么y值应为0.否则,它应该偏移先前设置的值v

对中的第二个元素必须是v的新值:

i%3==2 ? y : v

同样,根据请求的逻辑,当余数不是2时,v保持不变,否则将其设置为y的当前值。

因此reduce将在每次迭代中累积/更新这两个值,最后返回一对,其中只有第一个对我们感兴趣,这就是为什么最后有[0]的原因。

注释

由于您似乎正在寻找reduce实现,这就是我所使用的,但只要您的输出数组具有与输入数组一样多的元素(就像这里的情况一样),您也可以考虑使用map作为一个很好的选择(参见NinaScholz发布的回答)。

如果您打开较少的函数式编程方式,您也可以选择使用for循环并获得一些性能。

答案 3 :(得分:1)

可以通过减少来实现这一点 - 您只需要确定何时将每个第三个值清零以及何时找到当前值与其之前(第三个)值之间的差异。

使用更易理解的名称命名参数也有帮助。

&#13;
&#13;
var old_arr = [ [1, 1], [2, 8], [3, 12], [4, 13], [5, 23], [6, 30], [7, 41], [8, 44], [9, 50] ];
var new_arr = old_arr.reduce(function(result, value, index, arr) {
  if (index % 3 == 2) {
    return result.concat([[value[0], 0]]); // Set every third value to 0.
  } else {
    var prevIndex = index - (index % 3) - 1;
    var prevVal = prevIndex > -1 ? arr[prevIndex][1] : 0;
    return result.concat([[value[0], Math.abs(prevVal - value[1])]]);
  }
}, []);

console.log(JSON.stringify(new_arr)); // [[1,1],[2,8],[3,0],[4,1],[5,10],[6,0],[7,11],[8,3],[9,0]]
&#13;
&#13;
&#13;