Java层级关系集合转换

467 阅读1分钟

Background

平常很多情况下会遇到表中包含id、父id这种具有层级关系的数据,查询出来一个List集合,有时候需要后端转换成完整的层级结构。这里提供一种不需要递归的实现思路,且复杂度为O(n)。

Features

  • 支持泛型,任意具有层级结构的实体对象,只要包含id,父id,和子集合list的对象都可以使用该方法转换;
  • 浅克隆,会影响原始数据List集合;
  • 时间复杂度为n。

Code

/**
 * 层级转换工具类
 *
 * @author 是豆本豆呀
 * @date 2022-01-24 10:49:17
 */
public class LevelUtils<T, U> {
    /**
     * 层级结构转换
     *
     * @param data            层级数据
     * @param getIdFunc       获取id的方法
     * @param getPidFunc      获取父id的方法
     * @param getChildrenFunc 获取子集合的方法
     * @param setChildrenFunc 如果子集合为空,set子集合的方法
     * @return java.util.List<T>
     * @author 是豆本豆呀
     * @date 2022-01-24 11:23:28
     */
    public static <T, U> List<T> convert(List<T> data,
                                         Function<T, U> getIdFunc,
                                         Function<T, U> getPidFunc,
                                         Function<T, List<T>> getChildrenFunc,
                                         BiConsumer<T, List<T>> setChildrenFunc) {
        if (data == null) {
            return null;
        }
        Map<U, T> mapper = data.stream().collect(Collectors.toMap(getIdFunc, Function.identity()));

        List<T> result = new ArrayList<>();
        for (T element : data) {
            T parent = mapper.get(getPidFunc.apply(element));

            if (parent == null) {
                result.add(element);
                continue;
            }

            if (getChildrenFunc.apply(parent) == null) {
                setChildrenFunc.accept(parent, new ArrayList<>());
            }
            getChildrenFunc.apply(parent).add(element);
        }

        return result;
    }

    public static void main(String[] args) {
        @AllArgsConstructor
        @Data
        class Menu {
            private Integer id;
            private Integer pid;
            private String name;
            private List<Menu> children;
        }

        List<Menu> records = new ArrayList<>();
        records.add(new Menu(1, 0, "第一章", null));
        records.add(new Menu(2, 0, "第二章", null));
        records.add(new Menu(3, 0, "第三章", null));
        records.add(new Menu(21, 2, "第二章-第一节", null));
        records.add(new Menu(211, 21, "第二章-第一节-第一段", null));

        List<Menu> result = LevelUtils.convert(records, Menu::getId, Menu::getPid, Menu::getChildren, Menu::setChildren);
        System.out.println(JSONUtil.toJsonStr(result));
    }
}