5

次のようなデータがあるとします。

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 }]

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);

私にこれを与える:

rollup = [{key: "green", values: 4},
          {key: "red", values: 6}]

これはまさに私が欲しいものです。

ただし、私のデータの値は配列で構成されており、すべて同じ長さです:

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] }]

これらを同じように組み合わせることは可能ですか?たとえば、次のように指定します。

rollup = [{key: "green", values: [10,12,14,16]},
          {key: "red", values: [18,20,22,24]}]

これはおそらくd3ロールアップ機能を使用して可能だと思います(ただし、必ずしもd3を使用する必要はありません)。

解像度

@meetamit と @Superboggly の努力のおかげで、私には 3 つの解決策があります。

reduce()バージョン 1 (1回だけ使用するため推奨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];
      })
    };
  });
}

バージョン 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];
    });
  });
}

バージョン 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]);
}

このように呼び出されます:

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

そして、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]

アップデート

このメソッドは、入力行が 1 つでも関数を実行する必要がある場合には適していません。パート IIを参照

4

3 に答える 3

5

1 つのソリューションでは、次のものが使用[].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
  );
}

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);
于 2012-11-14T20:09:18.907 に答える
2

@meetamit reduce を使用するというあなたのアイデアが気に入っています。

d3 だけを使用してこれを解決したい場合は、ネスト関数と組み合わせて使用​​できる組み込みの reduce もあります。

var rollup = d3.nest().key(function(d) {
  return d[sum_by];
}).rollup(function(d) {
    var result = d.reduce(function(prev, cur, index, arr) {
        return prev.values.map(function(d,i) { return d + cur.values[i];});
    });

    return result;
}).entries(harvest);

必要に応じて、ここで遊ぶことができます。

于 2012-11-15T07:58:18.173 に答える