如何用D3.js同时实现按Zone分组、汇总统计并保留原始数据?
解决方案:结合分组、汇总与保留原始数据
你已经离目标很近啦!其实不用手动合并两次分组结果,不管是用d3.js还是原生JavaScript,都能在一次遍历/分组过程中同时完成汇总统计和保留原始数据,性能完全不用担心。
方法一:使用d3.js实现
d3.nest的rollup函数里不仅可以计算汇总值,还能直接把当前组的原始数据存下来,最后再调整一下结构就能得到你想要的结果:
var test = [ { "Name":"One Name", "Zip":"75001", "Zone":"A", "qty":60 }, { "Name":"Two Name", "Zip":"75003", "Zone":"A", "qty":40 }, { "Name":"Three Name", "Zip":"75009", "Zone":"B", "qty":20 } ]; const groupedResult = d3.nest() .key(function(d) { return d.Zone; }) .rollup(function(values) { // 在rollup里同时计算汇总值并保留原始数据 return { qtySum: d3.sum(values, function(d) { return d.qty; }), cnt: values.length, values: values // 直接存入当前组的原始数据数组 }; }) .entries(test) // 把d3.nest返回的key/value结构转换成你需要的格式 .map(function(group) { return { Zone: group.key, ...group.value }; }); console.log(groupedResult);
这个方法的优势是复用了你已经熟悉的d3.nest分组逻辑,所有操作都在分组流程中完成,不会有额外的性能开销。
方法二:原生JavaScript实现(无需依赖库)
如果不想依赖d3.js,用原生JS的reduce方法也能高效完成需求,只需要遍历一次原始数组:
var test = [ { "Name":"One Name", "Zip":"75001", "Zone":"A", "qty":60 }, { "Name":"Two Name", "Zip":"75003", "Zone":"A", "qty":40 }, { "Name":"Three Name", "Zip":"75009", "Zone":"B", "qty":20 } ]; const groupedResult = Object.values(test.reduce(function(acc, item) { const zone = item.Zone; // 如果当前区域还没在累加器里,初始化分组结构 if (!acc[zone]) { acc[zone] = { Zone: zone, qtySum: 0, cnt: 0, values: [] }; } // 更新汇总值和原始数据 acc[zone].qtySum += item.qty; acc[zone].cnt += 1; acc[zone].values.push(item); return acc; }, {})); console.log(groupedResult);
两种方法最终输出的结果都和你期望的完全一致,而且都是O(n)的时间复杂度,处理大数据量也很高效。
内容的提问来源于stack exchange,提问作者B-Ray
相关产品推荐
相关产品推荐

