如何用D3将数据按月份分组,获取含日均金额的数组Map?
用D3实现按月份分组的每日平均金额转换
嘿,刚接触D3的话,确实会对这些分组聚合的函数有点摸不着头脑,我来帮你搞定这个需求!
你的思路其实是对的,用d3.rollup已经完成了核心的聚合计算,只是需要把得到的嵌套Map转换成你想要的对象+数组格式就行。咱们一步步来:
核心问题分析
你写的d3.rollup代码得到的是一个嵌套Map(Map<string, Map<string, number>>),比如:
Map(1) {"jan" => Map(3) {"mon" => 4, "tue" => 2, "wed" => 2}}
而你需要把这个结构转换成普通对象,同时把每个月份下的每日Map转成指定格式的数组。另外要注意:原始数据里的amount是字符串,直接用d3.mean会计算错误,得先转成数字!
完整实现代码
const data = [ {day: "mon", amount: "4", month: "jan"}, {day: "tue", amount: "2", month: "jan"}, {day: "wed", amount: "3", month: "jan"}, {day: "wed", amount: "1", month: "jan"} ]; // 1. 用rollup完成聚合:按月份、日期分组,计算每日平均金额 const rolledUpData = d3.rollup( data, // 把amount转成数字后计算平均值 group => d3.mean(group, item => Number(item.amount)), item => item.month, // 第一层分组键:月份 item => item.day // 第二层分组键:日期 ); // 2. 把嵌套Map转换成目标格式 const result = Object.fromEntries( Array.from(rolledUpData.entries()).map(([month, dayAvgMap]) => [ month, // 把日期-平均值的Map转成指定的数组对象 Array.from(dayAvgMap.entries()).map(([day, avg]) => ({ day, avg_amount: avg.toString() // 转成字符串匹配你期望的输出格式 })) ]) ); console.log(result); // 输出正好是你要的:{"jan": [ {day:"mon", avg_amount:"4"}, {day:"tue", avg_amount:"2"}, {day:"wed", avg_amount:"2"} ]}
关键步骤解释
- 转数字计算平均值:原始数据的
amount是字符串类型,d3.mean处理字符串会得到NaN,所以必须用Number(item.amount)转成数字后再计算。 Object.fromEntries():把外层Map的键值对直接转换成普通对象的属性,比如把Map{"jan": ...}转成{"jan": ...}。- 内层Map转数组:用
Array.from(dayAvgMap.entries())把日期和平均值的Map转成[day, avg]的数组,再用map把每个元素转换成你需要的{day, avg_amount}对象,最后把平均值转成字符串匹配期望的输出。
这样就能完美得到你想要的结果啦!
内容的提问来源于stack exchange,提问作者michszm
相关产品推荐
相关产品推荐

