需求是这样的:数据库的数据是类似菜单那种的tree结构,产品想要搜索。 但是通过搜索出来数据就会构建不起一个tree。必须要保留没命中的父节点 。
初始树
/**
*
* 1
* / | \
* 2 3 4
* / \ /\
* 5 6 7 8
* / /\
* 11 9 10
* / \
* 12 13
*/
如果输入过滤条件 1,3,7,13:输入结果如下
/**
*
* 1
* / |
* 2 3
* / /
* 5 7
* /
* 11
* \
* 13
*/
废话少说,直接上代码
package com.jie.mini.controller.rest.sys.tree;
import lombok.Data;
import java.util.List;
/**
* 树节点
* @author jie
* @date 2021/3/9 11:53
*/
@Data
public class Node {
private Integer id;
private Integer parentId;
private List<Node> children;
public Node(Integer id ,Integer parentId) {
this.id = id;
this.parentId = parentId;
}
public Node() {
}
}
主要是根据isRemoveNode方法判断该节点是个应该删除
package com.jie.mini.controller.rest.sys.tree;
import org.apache.commons.collections.CollectionUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @author jie
* @date 2021/3/9 11:54
*/
public class Client {
public static void main(String[] args) {
/**
*
* 1
* / | \
* 2 3 4
* / \ /\
* 5 6 7 8
* / /\
* 11 9 10
* / \
* 12 13
*/
// 构建树
Node tree = initNode();
// 预设 命中的节点
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(7);
list.add(13);
Node node = filterTree(tree, list);
System.out.println(node);
/**
*
* 1
* / |
* 2 3
* / /
* 5 7
* /
* 11
* \
* 13
*/
}
/**
* 过滤树
* @param tree
* @param list
* @return
*/
private static Node filterTree(Node tree, List<Integer> list) {
if(isRemoveNode(tree, list)){
return null;
}
Iterator<Node> iterator = tree.getChildren().iterator();
while (iterator.hasNext()){
Node child = iterator.next();
deleteNode(child, iterator, list);
}
return tree;
}
/**
* 删除节点
* @param child
* @param iterator
* @param list
*/
private static void deleteNode(Node child, Iterator<Node> iterator, List<Integer> list) {
if(isRemoveNode(child,list)){
iterator.remove();
return;
}
List<Node> childrenList = child.getChildren();
if(CollectionUtils.isEmpty(childrenList)){
return;
}
Iterator<Node> children = childrenList.iterator();
while (children.hasNext()){
Node childChild = children.next();
deleteNode(childChild,children,list);
}
}
/**
* 判断该节点是否该删除
* @param root
* @param list 命中的节点
* @return ture 需要删除 false 不能被删除
*/
private static boolean isRemoveNode(Node root, List<Integer> list) {
List<Node> children = root.getChildren();
// 叶子节点
if(CollectionUtils.isEmpty(children)){
return !list.contains(root.getId());
}
// 子节点
if(list.contains(root.getId())){
return false;
}
// 如果存在一个子节点不能删除,那么就不能删除
boolean bool = true;
for (Node child : children) {
if(!isRemoveNode(child,list)){
bool = false;
break;
}
}
return bool;
}
/**
* 初始化树状结构
* 1
* / | \
* 2 3 4
* / \ /\
* 5 6 7 8
* / /\
* 11 9 10
* / \
* 12 13
*/
private static Node initNode() {
Node root = new Node(1,-1);
List<Node> rootChildren = new ArrayList<>();
Node node2= new Node(2, 1);
Node node3= new Node(3, 1);
Node node4= new Node(4, 1);
rootChildren.add(node2);
rootChildren.add(node3);
rootChildren.add(node4);
root.setChildren(rootChildren);
Node node5= new Node(5, 2);
Node node11= new Node(11, 5);
List<Node> node5Children = new ArrayList<>();
node5Children.add(node11);
node5.setChildren(node5Children);
Node node12= new Node(12, 11);
Node node13= new Node(13, 11);
List<Node> node11Children = new ArrayList<>();
node11Children.add(node12);
node11Children.add(node13);
node11.setChildren(node11Children);
Node node6= new Node(6, 2);
List<Node> node2Children = new ArrayList<>();
node2Children.add(node5);
node2Children.add(node6);
node2.setChildren(node2Children);
Node node7= new Node(7, 2);
Node node8= new Node(8, 2);
List<Node> node3Children = new ArrayList<>();
node3Children.add(node7);
node3Children.add(node8);
node3.setChildren(node3Children);
Node node9= new Node(9, 7);
Node node10= new Node(10, 7);
List<Node> node7Children = new ArrayList<>();
node7Children.add(node9);
node7Children.add(node10);
node7.setChildren(node7Children);
return root;
}
}
再贴一个开箱即用的工具类;实体实现TreeFilterModel.Node构造树;调用searchNode方法
package com.xxx.sone.admin.api.utils;
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author jie
* @date 2021/3/9 11:54
*/
public class TreeFilterModel<T extends TreeFilterModel.Node>{
/**
* 获取树状结构
* @param treeList搜索的树列表
* @param hitIds 命中的ids
* @return
*/
public List<T> searchNode(List<T> treeList,List<Integer> hitIds) {
List<T> filterTree = Lists.newArrayList();
for (T t : treeList) {
T node = filterTree(t, hitIds);
filterTree.add(node);
}
return filterTree.stream().filter(Objects::nonNull).collect(Collectors.toList());
}
/**
* 过滤树
* @param tree
* @param hitIds
* @return
*/
private T filterTree(T tree, List<Integer> hitIds) {
if(isRemoveNode(tree, hitIds)){
return null;
}
Iterator<T> iterator = (Iterator<T>)tree.getNodeChildren().iterator();
while (iterator.hasNext()){
T child = iterator.next();
deleteNode(child, iterator, hitIds);
}
return tree;
}
/**
* 删除节点
* @param child
* @param iterator
* @param hitIds
*/
private void deleteNode(T child, Iterator<T> iterator, List<Integer> hitIds) {
if(isRemoveNode(child, hitIds)){
iterator.remove();
return;
}
List<T> childrenList = (List<T>)child.getNodeChildren();
if(CollectionUtil.isEmpty(childrenList)){
return;
}
Iterator<T> children = childrenList.iterator();
while (children.hasNext()){
T childChild = children.next();
deleteNode(childChild,children, hitIds);
}
}
/**
* 判断该节点是否该删除
* @param root
* @param hitIds 命中的节点
* @return ture 需要删除 false 不能被删除
*/
private boolean isRemoveNode(T root, List<Integer> hitIds) {
List<T> children = (List<T>) root.getNodeChildren();
// 叶子节点
if(CollectionUtil.isEmpty(children)){
return !hitIds.contains(root.getNodeId());
}
// 子节点
if(hitIds.contains(root.getNodeId())){
return false;
}
boolean bool = true;
for (T child : children) {
if(!isRemoveNode(child,hitIds)){
bool = false;
break;
}
}
return bool;
}
public interface Node<T> {
/**
* 搜索节点的id
* @return
*/
Integer getNodeId();
/**
* 字节的列表
* @return
*/
List<T> getNodeChildren();
}
}