自定义列表转数(递归方式)
定义一个接口
接口如下展示
.
public interface Node<I> {
/**
* 获取Id
*
* @return id
*/
I getId();
/**
* 获取PID
*
* @return PID
*/
I getPid();
/**
* 设置子节点
*
* @param nodes 子节点
*/
void setNodes(Collection<? extends Node<I>> nodes);
业务代码
实际代码如下展示
.
public class Tree {
private Tree() {
}
/**
* 数据库中包含树结构的list 转真正的树
*
* @param source 原始树 数组结构
* @param rootId 根Id 可以为null
*/
public static <T extends Node<I>, I> Collection<T> tree(Collection<T> source,@Nullable I rootId) {
// 1. 获取根节点对象
Collection<T> roots = findRoots(source, rootId);
// 2.删除是为了减少遍历提高性能
source.removeAll(roots);
// 3.只有一条数据,没有叶子节点
if (source.isEmpty()) {
return roots;
}
// 4. 获取根节点下的子节点
for (T root : roots) {
// 这一步很有必要跳出递归
if (source.isEmpty()) {
break;
}
findLeaves(source, root);
}
return roots;
}
/**
* 获取一级根节点数组对象(包含根节点对象)
*/
private static <T extends Node<I>, I> Collection<T> findRoots(Collection<T> source, I rootId) {
Collection<T> rootNode = new ArrayList<>();
for (T node : source) {
if (Objects.equals(node.getPid(),rootId)) {
rootNode.add(node);
}
}
return rootNode;
}
/**
* 组装根节点下的叶子节点
*/
private static <T extends Node<I>, I> void findLeaves(Collection<T> source, T node) {
if (!source.isEmpty()) {
Collection<T> leaves = new ArrayList<>();
for (T sourceNode : source) {
if (node.getId().equals(sourceNode.getPid())) {
leaves.add(sourceNode);
}
}
node.setNodes(leaves.isEmpty() ? null : leaves);
// 有叶子节点说明他下一级还可能有叶子
if (!leaves.isEmpty()) {
for (T nested : leaves) {
findLeaves(source, nested);
}
// 在if内删除,可能剩余的"源"不是当前根的数据
source.removeAll(leaves);
}
}
}
}