Javascript求和数组,使用d3.nest()

Der*_*ill 5 javascript d3.js

如果我的数据看起来像这样:

harvest = [{type: "apple", color: "green", value: 1}, 
           {type: "apple", color: "red", value: 2}, 
           {type: "grape", color: "green", value: 3},
           {type: "grape", color: "red", value: 4 }]
Run Code Online (Sandbox Code Playgroud)

我可以使用d3的nest.rollup()函数通过各种属性来总结它:

sum_by = "color";

rollup = d3.nest().key(function(d) {
  return d[sum_by];
}).rollup(function(d) {
  return d3.sum(d, function(g) {
    return g.value;
  });
}).entries(harvest);
Run Code Online (Sandbox Code Playgroud)

给我这个:

rollup = [{key: "green", values: 4},
          {key: "red", values: 6}]
Run Code Online (Sandbox Code Playgroud)

这正是我想要的.

但是,我的数据中的值由数组组成,长度相等:

harvest = [{type: "apple", color: "green", values: [1,2,3,4]}, 
           {type: "apple", color: "red", values: [5,6,7,8]}, 
           {type: "grape", color: "green", values: [9,10,11,12]},
           {type: "grape", color: "red", values: [13,14,15,16] }]
Run Code Online (Sandbox Code Playgroud)

是否有可能以类似的方式组合这些?举个例子:

rollup = [{key: "green", values: [10,12,14,16]},
          {key: "red", values: [18,20,22,24]}]
Run Code Online (Sandbox Code Playgroud)

我觉得这可能是使用d3汇总功能(但不一定要使用d3).

解析度

感谢@meetamit和@Superboggly的努力,我有三个解决方案:

版本1(首选,因为它只使用reduce()一次而map()只使用一次):

function sumArrays(group) {
  return group.reduce(function(prev, cur, index, arr) {
    return {
      values: prev.values.map(function(d, i) {
        return d + cur.values[i];
      })
    };
  });
}
Run Code Online (Sandbox Code Playgroud)

版本2:

function sumArrays(group) {
  return group.map(function(h) {
    return h.values;
  }).reduce(function(prev, cur, index, arr) {
    return prev.map(function(d, i) {
      return d + cur[i];
    });
  });
}
Run Code Online (Sandbox Code Playgroud)

版本3(感兴趣,因为数组长度可能不同):

function sumArrays(group) {
  return group.reduce(function(prev, cur, index, arr) {
    return prev.map(function(d, i) {
      return d + cur.values[i];
    });
  }, [0, 0, 0, 0]);
}
Run Code Online (Sandbox Code Playgroud)

这样称呼:

function rollupArrays() {
  return d3.nest().key(function(d) {
    return d[sum_by];
  }).rollup(sumArrays).entries(harvest);
}
Run Code Online (Sandbox Code Playgroud)

并转换为CoffeeScript:

rollupArrays = ->
  d3.nest().key (d) ->
    d[sum_by]
  .rollup(sumArrays).entries(harvest)

sumArrays = (group) ->
  group.reduce (prev, cur, index, arr) ->
    values: prev.values.map (d,i) ->
      d + cur.values[i]
Run Code Online (Sandbox Code Playgroud)

UPDATE

如果函数必须运行,即使有一个输入行,此方法也不适用.见第二部分

mee*_*mit 5

一种解决方案使用[].reduce()和[].map():

// eg: sumArrays([ [1,2,3,4], [5,6,7,8] ]);// <- outputs [6, 8, 10, 12]
function sumArrays(arrays) {
  return arrays.reduce(
    function(memo, nums, i) {
      if(i == 0)
        return nums.concat();
      else
        return memo.map(
          function(memoNum, i) {
            return memoNum + nums[i];
          }
        );
    },
    [ ]// Start with empty Array for memo
  );
}
Run Code Online (Sandbox Code Playgroud)

reduce和map都不是旧JS中的原生,所以最好使用一个模块(下划线,或者可能有一个d3相当于reduce,但我还没有看到它).

编辑

在代码中使用它:

sum_by = "color";

rollup = d3.nest().key(function(d) {
  return d[sum_by];
}).rollup(function(d) {
  var arraysToSum = d.map(function(g) { return g.values; });
  return sumArrays(arraysToSum)
}).entries(harvest);
Run Code Online (Sandbox Code Playgroud)