d3.nest()求和对象数组数据

时间:2015-06-30 08:05:49

标签: javascript d3.js

我的数据格式为

data={
  "Month": "Jan",
  "typeA": [
     {
        "A": 24000,
        "B": 24000,
        "C": 24000
     }],
  "typeB": [
     {
        "A": 20000,
        "B": 14000,
        "C": 10000
     }],
  "typeC": [
     {
        "A": 34000,
        "B": 44000,
        "C": 54000
     }]
     },
      {
  "Month": "Feb",
  "typeA": [
     {
        "A": 84000,
        "B": 64000,
        "C": 14000
     }],
  "typeB": [
     {
        "A": 20000,
        "B": 34000,
        "C": 10000
     }],
  "typeC": [
     {
        "A": 30000,
        "B": 40000,
        "C": 50000
     }]
    }
    ]

我想计算每个类型的总和(即typeA,TypeB)的个别月份, 即我想要下面格式的数据,

Month: jan
typeA:72000
typeB:44000
typeC:13200

Month:feb
typeA:162000
typeB:64000
typeC:120000

我正在使用d3.nest()来实现这个目标,

这是我的代码,

    var months= d3.nest()
    .key(function (d) { return (d.Month) })
    .key(function (d) { return (d.typeA) })
    .key(function (d) { return (d.typeB) })
    .key(function (d) { return (d.typeC) })
      .rollup(function (leaves) {
          return d3.sum(leaves, function (d) { return d3.sum(sum,d3.values(d.A,d.B,d.C,d.D)) });
      })
      .entries(data);

我无法在这里获得元素的总和。我总和为零。谁能告诉我我做错了什么?

4 个答案:

答案 0 :(得分:1)

我对d3.nest不太熟悉。但我认为您可以使用JavaScript Array map函数获得结果。试试这段代码。

var data=[{
  "Month": "Jan",
  "typeA": [
     {
        "A": 24000,
        "B": 24000,
        "C": 24000
     }],
  "typeB": [
     {
        "A": 20000,
        "B": 14000,
        "C": 10000
     }],
  "typeC": [
     {
        "A": 34000,
        "B": 44000,
        "C": 54000
     }]
     },
      {
  "Month": "Feb",
  "typeA": [
     {
        "A": 84000,
        "B": 64000,
        "C": 14000
     }],
  "typeB": [
     {
        "A": 20000,
        "B": 34000,
        "C": 10000
     }],
  "typeC": [
     {
        "A": 30000,
        "B": 40000,
        "C": 50000
     }]
    }
  ];

var results = data.map(function(d){ 
  return { 
    Month: d.Month ,
    typeA: d3.sum(d3.values(d.typeA[0])),
    typeB: d3.sum(d3.values(d.typeB[0])),
    typeC: d3.sum(d3.values(d.typeC[0])) 
  } 
});

alert(JSON.stringify(results));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

答案 1 :(得分:1)

你可以像这样嵌套......

  data = [{
    "Month": "Jan",
    "typeA": [
      {
        "A": 24000,
        "B": 24000,
        "C": 24000
      }],
    "typeB": [
      {
        "A": 20000,
        "B": 14000,
        "C": 10000
      }],
    "typeC": [
      {
        "A": 34000,
        "B": 44000,
        "C": 54000
      }]
  },
  {
    "Month": "Feb",
    "typeA": [
      {
        "A": 84000,
        "B": 64000,
        "C": 14000
      }],
    "typeB": [
      {
        "A": 20000,
        "B": 34000,
        "C": 10000
      }],
    "typeC": [
      {
        "A": 30000,
        "B": 40000,
        "C": 50000
      }]
  }],
    months = d3.nest()

  var months = d3.nest()
    .key(function(d){return d.Month})
    .rollup(function(leaves){
      //leaves is an array so use d3.sum
      return d3.sum(leaves, function(d) {
        //d can be an object who's value can be an array
        //use d3.sum
        return d3.sum(d3.values(d), function(e){
          //
          return d3.sum(e, function(f) {
            return d3.sum(d3.values(f))
          });
        })
      } )
    })
    .entries(data);
  d3.select("#output").text(JSON.stringify(months));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="output"></div>

答案 2 :(得分:1)

您只需要像这样更改代码:

  1. 添加];的{​​{1}}

    data
  2. 将您的代码更改为:

    data = [
        {
            "Month": "Jan",
            "typeA": [
                {
                    "A": 24000,
                    "B": 24000,
                    "C": 24000
                }
            ],
            "typeB": [
                {
                    "A": 20000,
                    "B": 14000,
                    "C": 10000
                }
            ],
            "typeC": [
                {
                    "A": 34000,
                    "B": 44000,
                    "C": 54000
                }
            ]
        },
        {
            "Month": "Feb",
            "typeA": [
                {
                    "A": 84000,
                    "B": 64000,
                    "C": 14000
                }
            ],
            "typeB": [
                {
                    "A": 20000,
                    "B": 34000,
                    "C": 10000
                }
            ],
            "typeC": [
                {
                    "A": 30000,
                    "B": 40000,
                    "C": 50000
                }
            ]
        }
    ];
    

    修改 您也可以使用此类var months = d3.nest() .key(function(d) { return (d.Month) }) .rollup(function (v) { return { typeA: d3.sum(d3.values(v[0].typeA[0])), typeB: d3.sum(d3.values(v[0].typeB[0])), typeC: d3.sum(d3.values(v[0].typeC[0])) } }) .map(data); console.log(JSON.stringify(months)); 函数,但请记住,返回的值是d3.sum()'您在代码中遗漏的部分',以查看实际需要的结果解析数据。

    string

答案 3 :(得分:1)

不幸的是,我的另一个答案是针对不同的问题,但我会留下它,以防它有用。

@Gabriel的答案非常酷,但是使用的是d3功能,但它不是通用的,而且类别是硬编码的,这并不理想。

这是一种在(大多数)普通JS中完成通用的方法。唯一的假设是每个数组元素的第一个成员是被分组的标题,而其他成员是要卷起的标题。无论如何,以及通用,这种方式很短。

我还提供了@Gabriel答案的一个版本,以表明它也很容易概括。

  var data = [{
        "Month": "Jan",
        "typeA": [
          {
            "A": 24000,
            "B": 24000,
            "C": 24000
          }],
        "typeB": [
          {
            "A": 20000,
            "B": 14000,
            "C": 10000
          }],
        "typeC": [
          {
            "A": 34000,
            "B": 44000,
            "C": 54000
          }]
      },
      {
        "Month": "Feb",
        "typeA": [
          {
            "A": 84000,
            "B": 64000,
            "C": 14000
          }],
        "typeB": [
          {
            "A": 20000,
            "B": 34000,
            "C": 10000
          }],
        "typeC": [
          {
            "A": 30000,
            "B": 40000,
            "C": 50000
          }]
      }],
//////////////////////////////////////////////////////////////////////////////////
//Method one: without rollup
// assume that the first member of each object in the array is a heading
//  e.g. Month
//////////////////////////////////////////////////////////////////////////////////
  headings = data.reduce(function(headings, d) {
      var h = d3.keys(d)[0];  //get the heading
      return (headings [d[h]] = d3.keys(d).filter(function(p, i){return i}) //filter out the heading
        .reduce(function(s, p){   //sum each of the other members
          //p is the category being summed
          return (s[p] = d3.sum(d3.values(d[p][0])), s);
        }, {}), headings);
    }, {});

  d3.select("#output").text(JSON.stringify(headings));
//////////////////////////////////////////////////////////////////////////////////
//Method two: @Gabriel solution generalised
//////////////////////////////////////////////////////////////////////////////////
  var months = d3.nest()
    .key(function(d) { return (d.Month) })
    .rollup(function (v) {
      return d3.keys(v[0]).filter(function(p, i){return i}) //filter out the heading
        .reduce(function(s, p){   //sum each of the other members
          //p is the category being summed
          return (s[p] = d3.sum(d3.values(v[0][p][0])), s);
        }, {});
    })
    .map(data);

  d3.select("#output2").text(JSON.stringify(months));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="output"></div></br>
<div id="output2"></div>