树形数据逐级向上汇总-java

该文章描述了一种方法,用于对具有层级关系的树形数据结构中的每一项进行求和,上级的金额是下级所有金额的总和。通过在原始数据中添加leaf字段,然后遍历、过滤、分组、计算和更新数据,以及递归处理剩余的非叶子节点,最终构建出汇总后的树结构。提供的Java代码示例展示了这个过程。
摘要由CSDN通过智能技术生成


对树状指定结构的某一项,进行求和。上一级该项值,是下级所有该项之和(依次递归)。

举例最终结果形如:

[
    {
        "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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值