树形数据逐级向上汇总
对树状指定结构的某一项,进行求和。上一级该项值,是下级所有该项之和(依次递归)。
举例最终结果形如:
[
{
"id": 1,
"pid":null
"amount": "12011001",
"sonList": [
{
"id": 2,
"pid":1,
"amount": "12011001",
"sonList": [
{
"id": 3,
"pid":2,
"amount": "1001",
"sonList": [],
"leaf": true
},
{
"id": 4,
"pid":2,
"amount": "12010000",
"sonList": [],
"leaf": true
}
],
"leaf": false
}
],
"leaf": false
}
]
思路:
第一步,为源对象加入 leaf 字段,默认全部为false
第二步,拿出List集合,将最底层标记为叶子节点,leaf=true (没有子节点的对象为叶子节点),并将该集合复制一份作为操作数据集合 nt
第三步,对复制出来的集合进行过滤,如果为叶子 leaf=true,取pid为key,对象塞入list为value,生成Map
第四步,根据Map的key分别求和,并从原数据过滤 id = pid 的数据,将和塞入该父节点的值,并将父节点 leaf设置为true
第五步,将复制出来的操作数据集合 nt 中,所有参与计算的叶子节点移除
第六步,判断是否存在叶子节点,不存在结束,存在递归调用第三步
第七步,根据list集合对应成Tree状结构
第三步到第六步 代码:
(注:前面有所简化,部分字段和代码不一致 id对应itemCode,pid对应preCode)
/**
* 逐层计算
* @param allItems 全部数据
* @param nt copy出来的数据
*/
private void countForSon(List<FundmanageBudgetItemTreeRo> allItems, List<FundmanageBudgetItemTreeRo> nt) {
if (null == nt) {
nt = new ArrayList<>(allItems);
}
Map<String, List<FundmanageBudgetItemTreeRo>> temp = nt.stream().filter(FundmanageBudgetItemTreeRo::isLeaf).collect(Collectors.groupingBy(FundmanageBudgetItemTreeRo::getPreCode));
for (String preCode : temp.keySet()) {
List<FundmanageBudgetItemTreeRo> fundmanageBudgetItemTreeRos = temp.get(preCode);
BigDecimal amount = new BigDecimal("0");
for (FundmanageBudgetItemTreeRo fundmanageBudgetItemTreeRo : fundmanageBudgetItemTreeRos) {
amount = amount.add(new BigDecimal(fundmanageBudgetItemTreeRo.getAmount()));
nt.remove(fundmanageBudgetItemTreeRo);
}
Optional<FundmanageBudgetItemTreeRo> first = allItems.stream().filter(it -> it.getItemCode().equals(preCode)).findFirst();
if (first.isPresent()) {
if (!StringUtils.isEmpty(first.get().getAmount())) {
amount = amount.add(new BigDecimal(first.get().getAmount()));
}
first.get().setAmount(amount.toString());
}
nt.stream().filter(it -> it.getItemCode().equals(preCode)).peek(it -> it.setLeaf(true)).collect(Collectors.toList());
}
if (nt.size() != 0 && temp.keySet().size() != 0) {
this.countForSon(allItems, nt);
}
}
第七步生成树代码
private FundmanageBudgetItemTreeRo buildTree(FundmanageBudgetItemTreeRo root, List<FundmanageBudgetItemTreeRo> allItems) {
if (null == root.getSonList()) {
root.setSonList(new ArrayList<>());
}
List<FundmanageBudgetItemTreeRo> collect = allItems.stream().filter(it -> it.getPreCode().equals(root.getItemCode())).peek(it -> {
FundmanageBudgetItemTreeRo son = new FundmanageBudgetItemTreeRo();
BeanUtils.copyProperties(it, son);
root.getSonList().add(son);
}).collect(Collectors.toList());
for (FundmanageBudgetItemTreeRo treeRo : collect) {
this.buildTree(treeRo, allItems);
}
return root;
}