列表转树结构,清除无子节点的节点,获取节点到根的路径

列表转树结构

逻辑上呈树结构的数据,诸如菜单,省市区,在数据库中单表存放,Java程序从数据库中读取出来这些数据时,是列表形式。列表转树结构使用双层for循环实现:

    /**
     * 节点组成树形结构,返回森林
     *
     * @param list      节点列表
     * @param predicate 定义树的根节点
     * @return 森林
     */
    static <T extends ITree<T>> List<T> toForest(List<T> list, Predicate<T> predicate) {
        for (T item : list) {
            List<T> children = list.stream()
                    .filter(c -> Objects.equals(c.getParentId(), item.getId()))
                    .collect(Collectors.toList());
            item.setChildren(children);
        }
        List<T> tree = list.stream().filter(predicate)
                .collect(Collectors.toList());
        return tree;
    }

清除空目录

    /**
     * 清除空的子目录
     */
    private void clearEmptyChildren(DaCalGroup group) {
        Iterator<DaCalGroup> iterator = group.getChildren().iterator();
        while (iterator.hasNext()) {
            DaCalGroup child = iterator.next();
            if (child.getGroupType() == 1L) continue;
            clearEmptyChildren(child);
            if (child.getChildren().isEmpty()) {
                iterator.remove();
            }
        }
    }

获取节点至根的路径

使用递归的样例代码如下:

    /**
     * 例如 areaCode=130400时,返回河北省邯郸市
     * 例如 areaCode=130000时,返回河北省
     *
     * @param areaCode 省、市、区级编码
     * @return 从省级全名拼接到areaCode全名的路径
     */
    public String getPathFullname(String areaCode) {
        AreaDict areaDict = dao.findByAreaCode(areaCode).orElse(null);
        if (areaDict == null) return "";
        if (!COUNTRY_CODE.equals(areaDict.getParentCode())) {
            return getPathFullname(areaDict.getParentCode()) + areaDict.getFullname();
        }
        return areaDict.getFullname();
    }

可以优化为使用双层for循环,list保存中间的迭代结果的方式,替代递归。
伪代码:

function(areaCode){
  List list = new List();
  list.add(areaCode)
  while(list.tail is not root){
    list.add(parent(list.tail))
  }
  return list.reverse().join()
}
posted @ 2023-07-06 09:11  豆苗稀  阅读(33)  评论(0编辑  收藏  举报