树型结构构建,模糊查询,过滤

2024-02-02 12:44

本文主要是介绍树型结构构建,模糊查询,过滤,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、前言

1、最近在做甘特图,有些需求和树型结构要求很大,看的是 pingCode,有搜索

在这里插入图片描述
2、还有抽取一部分树型结构的,如下是抽取上面的结构类型为需求的,重新组成树型

在这里插入图片描述

二、构建多颗树型结构

1、某些业务下,从数据库查询出来一堆数据后,希望构建树型结构,但是存在一种情况就是,可能这堆数据不是完整的,比如如下情况,我查询出来了除了D节点外的所有数据,那么这种情况下,如果使用正常的构建方式,那么构建出来的数据会丢失数据H,I,J,M,即使这四个节点的数据已经查询出来了,但是因为D节点缺失,导致无法链接上,如果是中间断开了,那断开的部分单独成一个树型结构
在这里插入图片描述

2、那有人说这不是正常的吗,你为啥D节点不查询出来,一颗完整的树是这样的啊,但是存在一些业务情况如下,上述的数据中除了D节点,其它节点的类型都是type1,而D节点的Type 是2,我现在就是想看type为1的,然后你给我形成树型结构

3、代码如下,其中模拟的时候,缺失节点999,所以结果如下,把节点999那一条结构,单独做一个树型结构返回,避免丢失
在这里插入图片描述

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;import java.util.*;
import java.util.stream.Collectors;class ChildHandle {public static void main(String[] args) {List<Node> mockData = mockData();List<List<Node>> lists = buildTree(mockData, 50);System.out.println(JSON.toJSONString(lists));}public static List<List<Node>> buildTree(List<Node> data, int maxDepth) {List<List<Node>> multipleTopNodeTreeResult = new ArrayList<>();if (CollUtil.isEmpty(data)) {return multipleTopNodeTreeResult;}Map<Integer, List<Node>> moduleMap = new HashMap<>(32);// 找出所有的父节点,因为有些数据并不是一个完整的树型树,如果是中间断开了,那断开的部分单独成一个树型结构HashSet<Integer> rootIds = new HashSet<>();Set<Integer> allIds = data.stream().map(Node::getId).collect(Collectors.toSet());for (Node module : data) {moduleMap.putIfAbsent(module.getPid(), new ArrayList<>());moduleMap.get(module.getPid()).add(module);// 当前的item的pid对应的数据不存在,说明从当前的item的pid就断开了,则为这个pid单独起一颗树if (!allIds.contains(module.getPid())) {rootIds.add(module.getPid());}}// 根据上述的判断,已经知道存在几颗树,则为每颗树构建结构rootIds.forEach(curTopNodeId -> {// 处理每一颗树List<Node> treeInCurTopNode = moduleMap.get(curTopNodeId);if (treeInCurTopNode != null) {// Sort root modulestreeInCurTopNode.sort(Comparator.comparingInt(Node::getSerialNumber));for (Node rootModule : treeInCurTopNode) {buildChildren(rootModule, moduleMap, 0, maxDepth);}} else {treeInCurTopNode = new ArrayList<>();}multipleTopNodeTreeResult.add(treeInCurTopNode);});return multipleTopNodeTreeResult;}private static void buildChildren(Node parentModule, Map<Integer, List<Node>> moduleMap, int depth, int maxDepth) {if (depth >= maxDepth) {// 达到深度限制,停止递归return;}List<Node> children = moduleMap.get(parentModule.getId());if (children != null) {// Sort childrenchildren.sort(Comparator.comparingInt(Node::getSerialNumber));parentModule.setChildren(children);for (Node child : children) {// 增加深度计数 限制最多递归多少次,避免OOMbuildChildren(child, moduleMap, depth + 1, maxDepth);}}}/*** 模拟数据** @return*/private static List<Node> mockData() {List<Node> result = new ArrayList<>();result.add(new Node(1, 0, "Root1"));result.add(new Node(2, 1, "Root1 A"));result.add(new Node(3, 1, "Root1 B"));result.add(new Node(4, 2, "Root1 A.1"));result.add(new Node(5, 2, "Root1 A.2"));result.add(new Node(6, 3, "Root1 B.1"));result.add(new Node(7, 3, "Root1 B.2"));result.add(new Node(8, 3, "Root1 C"));result.add(new Node(9, 8, "Root1 D"));result.add(new Node(1000, 0, "Root2"));result.add(new Node(1001, 1000, "Root2 A"));result.add(new Node(1002, 1000, "Root2 B"));return result;}
}class Node {private Integer id;/*** 父id,为0时说明自己就是第一层*/private Integer pid;/*** 名称*/private String name;/*** 排序*/private int serialNumber;/*** 子集*/private List<Node> children;public Integer getPid() {return pid;}public void setPid(Integer pid) {this.pid = pid;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<Node> getChildren() {return children;}public void setChildren(List<Node> children) {this.children = children;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public int getSerialNumber() {return serialNumber;}public void setSerialNumber(int serialNumber) {this.serialNumber = serialNumber;}public Node(Integer id, Integer pid, String name) {this.id = id;this.pid = pid;this.name = name;}public Node(Integer id, Integer pid, String name, int serialNumber, List<Node> children) {this.id = id;this.pid = pid;this.name = name;this.serialNumber = serialNumber;this.children = children;}
}

三、树型结构查询过滤

1、方法如下,其中存在一种情况就是查询到父节点满足过滤条件后,那么需不需要判断其子节点是否满足条件,如果不需要注释那段代码即可,如果需要接着往下判断则需要加上

/*** 树型查询** @param tree          树型集合* @param key           搜索的字段名称* @param value         搜索的值* @param childNodeName 子节点名称* @param <T>           数据具体对象* @return tree*/public <T> List<T> filterTree(List<T> tree, Function<JSONObject, Boolean> filterCondition, String childNodeName) {// 这个方法的原始文章 https://blog.csdn.net/weixin_44748212/article/details/131692471// 如果要保留子节点的话把注释的(// 去除子节点start - end )这段代码删掉即可if (CollUtil.isEmpty(tree)) {return new ArrayList<>();}
//        JSONArray arr = JSONArray.parseArray(JSON.toJSONString(tree)); //如果直接序列化,时间格式是 时间戳了JSONArray arr = JSONArray.parseArray(JSON.toJSONStringWithDateFormat(tree, DatePattern.NORM_DATETIME_PATTERN));JSONArray result = filterTree(arr, filterCondition, childNodeName);Type listType = new TypeReference<List<T>>() {}.getType();return JSON.parseObject(result.toJSONString(), listType);}private JSONArray filterTree(JSONArray tree, Function<JSONObject, Boolean> filterCondition, String childNodeName) {Iterator<Object> it = tree.iterator();while (it.hasNext()) {JSONObject current = (JSONObject) it.next();// 把当前节点给到外部,让外部判断是否满足条件if (Boolean.TRUE.equals(filterCondition.apply(current))) {// 去除子节点 startJSONArray childNodes = current.getJSONArray(childNodeName);if (!CollUtil.isEmpty(childNodes)) {JSONArray filterTree = filterTree(childNodes, filterCondition, childNodeName);if (CollUtil.isEmpty(filterTree)) {current.put(childNodeName, new JSONArray());}}// 去除子节点 endcontinue;}JSONArray childNodes = current.getJSONArray(childNodeName);if (!CollUtil.isEmpty(childNodes)) {filterTree(childNodes, filterCondition, childNodeName);}if (CollUtil.isEmpty(childNodes)) {it.remove();}}return tree;}

2、使用方式

List<ListDto> curTreeFilterResult = filterTree(curTree, currentNode -> {String titleValue = currentNode.getString("title");int serialNumber = currentNode.getIntValue("serialNumber");return StrUtil.contains(titleValue, params.getQuery())|| StrUtil.contains(dbDevmProjectInfo.getIdentifier().concat("-" + serialNumber), params.getQuery());}, "children");if (CollUtil.isNotEmpty(curTreeFilterResult)) {filterTreeResult.add(curTreeFilterResult);}

这篇关于树型结构构建,模糊查询,过滤的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/670746

相关文章

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

MyBatis Plus大数据量查询慢原因分析及解决

《MyBatisPlus大数据量查询慢原因分析及解决》大数据量查询慢常因全表扫描、分页不当、索引缺失、内存占用高及ORM开销,优化措施包括分页查询、流式读取、SQL优化、批处理、多数据源、结果集二次... 目录大数据量查询慢的常见原因优化方案高级方案配置调优监控与诊断总结大数据量查询慢的常见原因MyBAT

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

基于Go语言开发一个 IP 归属地查询接口工具

《基于Go语言开发一个IP归属地查询接口工具》在日常开发中,IP地址归属地查询是一个常见需求,本文将带大家使用Go语言快速开发一个IP归属地查询接口服务,有需要的小伙伴可以了解下... 目录功能目标技术栈项目结构核心代码(main.go)使用方法扩展功能总结在日常开发中,IP 地址归属地查询是一个常见需求:

MySQL之复合查询使用及说明

《MySQL之复合查询使用及说明》文章讲解了SQL复合查询中emp、dept、salgrade三张表的使用,涵盖多表连接、自连接、子查询(单行/多行/多列)及合并查询(UNION/UNIONALL)等... 目录复合查询基本查询回顾多表查询笛卡尔积自连接子查询单行子查询多行子查询多列子查询在from子句中使

Docker多阶段镜像构建与缓存利用性能优化实践指南

《Docker多阶段镜像构建与缓存利用性能优化实践指南》这篇文章将从原理层面深入解析Docker多阶段构建与缓存机制,结合实际项目示例,说明如何有效利用构建缓存,组织镜像层次,最大化提升构建速度并减少... 目录一、技术背景与应用场景二、核心原理深入分析三、关键 dockerfile 解读3.1 Docke

Vue3 如何通过json配置生成查询表单

《Vue3如何通过json配置生成查询表单》本文给大家介绍Vue3如何通过json配置生成查询表单,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录功能实现背景项目代码案例功能实现背景通过vue3实现后台管理项目一定含有表格功能,通常离不开表单

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可