You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于自关联BOOKS表与Java类,如何构建层级化图书展示列表?

实现扁平图书列表到层级系列结构的高效方案

核心思路

利用哈希表快速定位父节点,先将所有图书按ID建立索引映射,再通过遍历将子节点挂载到对应父节点的volumes列表中,最后筛选出顶级节点即可。由于层级最多4级,无论迭代还是递归都能高效完成,无需复杂逻辑。

具体步骤

  • 构建图书索引映射:把扁平列表里的所有Book对象存入HashMap<String, Book>,键为BOOK_ID,实现O(1)时间复杂度的父节点查找,避免重复遍历列表。
  • 转换并挂载子节点:
    1. 遍历每本图书,若其SERIES_ID不为空,从映射中取出对应的父节点。
    2. 若父节点是普通Book,将其转换为Series实例(继承关系支持属性复制转换),并初始化volumes列表。
    3. 将当前图书添加到父节点的volumes列表,同时按SERIES_VOL_NUM排序,保证卷号顺序符合展示需求。
  • 收集顶级节点:筛选出SERIES_ID为空的节点,这些就是层级结构的顶级项(包括独立图书和顶级系列)。

代码实现示例

import java.util.*;
import java.util.stream.Collectors;

public class BookHierarchyBuilder {

    public static List<Book> buildHierarchy(List<Book> flatBooks) {
        // 构建ID到Book的映射,快速查找父节点
        Map<String, Book> bookMap = flatBooks.stream()
                .collect(Collectors.toMap(Book::getBookId, book -> book));

        // 遍历处理所有子节点挂载
        for (Book book : flatBooks) {
            String seriesId = book.getSeriesId();
            if (seriesId != null && bookMap.containsKey(seriesId)) {
                Book parentBook = bookMap.get(seriesId);
                Series parentSeries;

                // 父节点为普通Book时,转换为Series类型
                if (!(parentBook instanceof Series)) {
                    parentSeries = convertBookToSeries(parentBook);
                    bookMap.put(seriesId, parentSeries); // 更新映射中的父节点实例
                } else {
                    parentSeries = (Series) parentBook;
                }

                // 添加当前图书并按卷号排序
                List<Book> volumes = Optional.ofNullable(parentSeries.getVolumes())
                        .orElseGet(ArrayList::new);
                volumes.add(book);
                volumes.sort(Comparator.comparing(Book::getSeriesVolNum, Comparator.nullsLast(Integer::compare)));
                parentSeries.setVolumes(volumes);
            }
        }

        // 收集所有顶级节点(无父节点的图书/系列)
        return flatBooks.stream()
                .filter(book -> book.getSeriesId() == null)
                .map(book -> bookMap.get(book.getBookId()))
                .collect(Collectors.toList());
    }

    // 将普通Book转换为Series,复制所有属性
    private static Series convertBookToSeries(Book book) {
        Series series = new Series();
        series.setBookId(book.getBookId());
        series.setTitle(book.getTitle());
        series.setUrl(book.getUrl());
        series.setPublishedOn(book.getPublishedOn());
        series.setIsbn(book.getIsbn());
        series.setAnnotation(book.getAnnotation());
        series.setCommentary(book.getCommentary());
        series.setRating(book.getRating());
        series.setSeriesId(book.getSeriesId());
        series.setSeriesVolNum(book.getSeriesVolNum());
        series.setVolumes(new ArrayList<>());
        return series;
    }
}

额外说明

  • 时间复杂度:整体为O(n log n),主要来自卷号排序操作,其余步骤均为O(n),处理图书列表效率足够。
  • 层级适配:即使嵌套到4级,上述逻辑会自动处理父节点的转换与挂载,无需额外的层级判断。
  • 空值兼容:排序逻辑兼容SERIES_VOL_NUM为空的情况,将这类条目放在系列末尾。

内容的提问来源于stack exchange,提问作者Gary Greenberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 23:40:27