com.wl4g.infra.common.function.TreeConvertor Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2017 ~ 2025 the original author or authors. James Wong
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.wl4g.infra.common.function;
import static com.wl4g.infra.common.lang.Assert2.notNullOf;
import static java.lang.String.valueOf;
import static java.util.Objects.nonNull;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import javax.validation.constraints.NotNull;
import org.apache.commons.lang3.StringUtils;
import com.wl4g.infra.common.annotation.Todo;
import com.wl4g.infra.common.function.TreeConvertor.TreeNode;
/**
*
* 平面(List)树与children树互转器. {@link TreeConvertor}
*
* @author James Wong
* @version v1.0 2017-09-08
* @since
* @param
*/
@NotThreadSafe
public class TreeConvertor> {
private final ID rootParentId;
private final NodeIdMatcher matcher;
private final List childrens = new ArrayList<>();
private final List flatNodes = new ArrayList<>();
@SuppressWarnings("unchecked")
public TreeConvertor() {
this(null, (NodeIdMatcher) NodeIdMatcher.DEFAULT);
}
public TreeConvertor(@Nullable ID rootParentId, @NotNull NodeIdMatcher matcher) {
this.rootParentId = rootParentId;
this.matcher = notNullOf(matcher, "matcher");
}
/**
* 将平面树格式化为children树
*
* @param flatTree
* 平面结构的树列表
* @param isFilterLowest
* 是否过滤(每层)最低级的节点
* @return 返回包含children节点关系的树
*/
public List formatToChildren(List flatTree, boolean isFilterLowest) {
// 1.1 parse children tree.
List childrenTree = new ArrayList(flatTree.size() / 2);
for (E n : flatTree) {
if (n != null && matcher.eq(n.getParentId(), rootParentId)) {
childrenTree.add(n);
}
for (E t : flatTree) {
if (nonNull(t) && nonNull(n) && matcher.eq(t.getParentId(), n.getId())) {
if (emptyChildrens(n)) {
List childrens = new ArrayList();
childrens.add(t);
n.setChildrens(childrens);
} else {
n.getChildrens().add(t);
}
}
}
}
// 2.1 filter children.
childrenTree = isFilterLowest ? filterChildren(childrenTree) : childrenTree;
// 2.2 recursion level/total set.
return childrenLevelSet(null, childrenTree);
}
/**
* 将children解析为平面树
*
* @param treeNodes
* children结构的树列表
* @return 返回不包含children节点关系(以parentId做父子关系)的平面树
*/
public List parseChildren(List treeNodes) {
if (treeNodes != null) {
for (E n : treeNodes) {
if (!emptyChildrens(n)) {
parseChildren(n.getChildrens());
n.getChildrens().clear();
}
flatNodes.add(n);
}
}
return flatNodes;
}
/**
* 依据父ID获取所有子、孙等节点列表
*
* @param childrenTree
* children树列表
* @param pId
* 目标父级ID
* @return 返回包含pId以及所有子、孙节点
*/
public List subChildrens(List childrenTree, ID parentId) {
if (childrenTree != null) {
for (E t : childrenTree) {
if (matcher.eq(t.getId(), parentId)) {
childrens.add(t);
}
// 继续递归直到找到匹配节点为止.
subChildrens(t.getChildrens(), parentId);
}
}
return childrens;
}
/**
* 子节点递归level设置
*
* @param parent
* 父节点
* @param childrenTree
* 对应子节点列表
* @return
* @sine
*/
private List childrenLevelSet(E parent, List childrenTree) {
for (E t : childrenTree) {
if (matcher.eq(t.getParentId(), rootParentId)) {
t.setLevel(0);
} else if (parent != null) {
increaseLevel(t, parent.getLevel());
}
if (!emptyChildrens(t)) {
// 继续递归下级节点.
childrenLevelSet(t, t.getChildrens());
}
}
return childrenTree;
}
/**
* 递归过滤最底层节点
* 注: List做删除时不能直接用list.get(i).remove(object);
* http://www.cnblogs.com/zhangfei/p/4510584.html
*
* @param childrenTree
* @return
*/
private List filterChildren(List childrenTree) {
final Iterator it = childrenTree.iterator();
while (it.hasNext()) {
final E t = it.next();
if (!emptyChildrens(t)) {
// 继续递归直到找到匹配节点为止.
filterChildren(t.getChildrens());
} else {
it.remove();
}
}
return childrenTree;
}
/**
* 是否存在子节点
*
* @param t
* @return
*/
private boolean emptyChildrens(E t) {
return (t.getChildrens() == null || t.getChildrens().isEmpty());
}
/**
* 增加设置节点level
*
* @param t
* 目标节点
* @param parentLevel
* 父节点级别
*/
private void increaseLevel(E t, int parentLevel) {
t.setLevel(++parentLevel);
}
/**
* 子节点递归累加设置
*
* @param t
* @param parentLevel
*/
@Todo
public List childrenTotalSet(List childrenTree) {
// TODO
// for (E t : childrenTree) {
// if (matcher.eq(t.getParentId(), rootParentId)) {
// // Map nodeSubs = new HashMap();
// t.setSum(0);
// }
// if (!emptyChildrens(t)) {
// // 继续递归下级节点.
// childrenTotalSet(t, t.getChildrens());
// }
// }
return childrenTree;
}
/**
* TreeConvert转换器节点操作接口. {@link TreeNode}
*
* @author James Wong
* @version v1.0 2017-09-08
* @since
* @param
*/
public static interface TreeNode extends Serializable {
// --- Tree node basic. ---
ID getId();
void setId(ID id);
ID getParentId();
void setParentId(ID parentId);
int getLevel();
void setLevel(int level);
List getChildrens();
void setChildrens(List childrens);
// --- Node statistics. ---
default int getCount() {
// Ignore
return -1;
}
default void setCount(int count) {
// Ignore
}
default Double getSum() {
// Ignore
return null;
}
default void setSum(Double sum) {
// Ignore
}
default Double getValue() {
// Ignore
return null;
}
default void setValue(Double data) {
// Ignore
}
}
public static interface NodeIdMatcher {
/**
* Check nodes ID is equals.
*
* @param nodeId1
* @param nodeId2
* @return
*/
boolean eq(ID nodeId1, ID nodeId2);
/**
* Default {@link NodeIdMatcher} instance of string equals.
*/
public static final NodeIdMatcher