mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add method for Tree
This commit is contained in:
parent
bb1e4ba76a
commit
ab1d8e84e4
@ -10,6 +10,7 @@
|
|||||||
* 【http 】 增加HttpResource(issue#1943@Github)
|
* 【http 】 增加HttpResource(issue#1943@Github)
|
||||||
* 【http 】 增加BytesBody、FormUrlEncodedBody
|
* 【http 】 增加BytesBody、FormUrlEncodedBody
|
||||||
* 【cron 】 TaskTable.remove增加返回值(issue#I4HX3B@Gitee)
|
* 【cron 】 TaskTable.remove增加返回值(issue#I4HX3B@Gitee)
|
||||||
|
* 【core 】 Tree增加filter、filterNew、cloneTree、hasChild方法(issue#I4HFC6@Gitee)
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
||||||
* 【core 】 修复FileResource构造fileName参数无效问题(issue#1942@Github)
|
* 【core 】 修复FileResource构造fileName参数无效问题(issue#1942@Github)
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package cn.hutool.core.lang.tree;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.lang.Filter;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.CharUtil;
|
import cn.hutool.core.util.CharUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
@ -21,7 +22,7 @@ import java.util.function.Consumer;
|
|||||||
* @author liangbaikai
|
* @author liangbaikai
|
||||||
* @since 5.2.1
|
* @since 5.2.1
|
||||||
*/
|
*/
|
||||||
public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
public class Tree<T> extends LinkedHashMap<String, Object> implements Node<T> {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final TreeNodeConfig treeNodeConfig;
|
private final TreeNodeConfig treeNodeConfig;
|
||||||
@ -175,6 +176,16 @@ import java.util.function.Consumer;
|
|||||||
return (List<Tree<T>>) this.get(treeNodeConfig.getChildrenKey());
|
return (List<Tree<T>>) this.get(treeNodeConfig.getChildrenKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有子节点,无子节点则此为叶子节点
|
||||||
|
*
|
||||||
|
* @return 是否有子节点
|
||||||
|
* @since 5.7.17
|
||||||
|
*/
|
||||||
|
public boolean hasChild() {
|
||||||
|
return CollUtil.isNotEmpty(getChildren());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归树并处理子树下的节点:
|
* 递归树并处理子树下的节点:
|
||||||
*
|
*
|
||||||
@ -184,18 +195,67 @@ import java.util.function.Consumer;
|
|||||||
public void walk(Consumer<Tree<T>> consumer) {
|
public void walk(Consumer<Tree<T>> consumer) {
|
||||||
consumer.accept(this);
|
consumer.accept(this);
|
||||||
final List<Tree<T>> children = getChildren();
|
final List<Tree<T>> children = getChildren();
|
||||||
if(CollUtil.isNotEmpty(children)){
|
if (CollUtil.isNotEmpty(children)) {
|
||||||
children.forEach((tree)-> tree.walk(consumer));
|
children.forEach((tree) -> tree.walk(consumer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归过滤并生成新的树<br>
|
||||||
|
* 通过{@link Filter}指定的过滤规则,本节点或子节点满足过滤条件,则保留当前节点,否则抛弃节点及其子节点
|
||||||
|
*
|
||||||
|
* @param filter 节点过滤规则函数,只需处理本级节点本身即可
|
||||||
|
* @return 过滤后的节点,{@code null} 表示不满足过滤要求,丢弃之
|
||||||
|
* @see #filter(Filter)
|
||||||
|
* @since 5.7.17
|
||||||
|
*/
|
||||||
|
public Tree<T> filterNew(Filter<Tree<T>> filter) {
|
||||||
|
return cloneTree().filter(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归过滤当前树,注意此方法会修改当前树<br>
|
||||||
|
* 通过{@link Filter}指定的过滤规则,本节点或子节点满足过滤条件,则保留当前节点,否则抛弃节点及其子节点
|
||||||
|
*
|
||||||
|
* @param filter 节点过滤规则函数,只需处理本级节点本身即可
|
||||||
|
* @return 过滤后的节点,{@code null} 表示不满足过滤要求,丢弃之
|
||||||
|
* @see #filterNew(Filter)
|
||||||
|
* @since 5.7.17
|
||||||
|
*/
|
||||||
|
public Tree<T> filter(Filter<Tree<T>> filter) {
|
||||||
|
final List<Tree<T>> children = getChildren();
|
||||||
|
if (CollUtil.isNotEmpty(children)) {
|
||||||
|
// 递归过滤子节点
|
||||||
|
final List<Tree<T>> filteredChildren = new ArrayList<>(children.size());
|
||||||
|
Tree<T> filteredChild;
|
||||||
|
for (Tree<T> child : children) {
|
||||||
|
filteredChild = child.filter(filter);
|
||||||
|
if (null != filteredChild) {
|
||||||
|
filteredChildren.add(filteredChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(CollUtil.isNotEmpty(filteredChildren)){
|
||||||
|
// 子节点有符合过滤条件的节点,则本节点保留
|
||||||
|
return this.setChildren(filteredChildren);
|
||||||
|
} else {
|
||||||
|
this.setChildren(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 子节点都不符合过滤条件,检查本节点
|
||||||
|
return filter.accept(this) ? this : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置子节点,设置后会覆盖所有原有子节点
|
* 设置子节点,设置后会覆盖所有原有子节点
|
||||||
*
|
*
|
||||||
* @param children 子节点列表
|
* @param children 子节点列表,如果为{@code null}表示移除子节点
|
||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
public Tree<T> setChildren(List<Tree<T>> children) {
|
public Tree<T> setChildren(List<Tree<T>> children) {
|
||||||
|
if(null == children){
|
||||||
|
this.remove(treeNodeConfig.getChildrenKey());
|
||||||
|
}
|
||||||
this.put(treeNodeConfig.getChildrenKey(), children);
|
this.put(treeNodeConfig.getChildrenKey(), children);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -241,6 +301,34 @@ import java.util.function.Consumer;
|
|||||||
return stringWriter.toString();
|
return stringWriter.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归克隆当前节点(即克隆整个树,保留字段值)<br>
|
||||||
|
* 注意,此方法只会克隆节点,节点属性如果是引用类型,不会克隆
|
||||||
|
*
|
||||||
|
* @return 新的节点
|
||||||
|
* @since 5.7.17
|
||||||
|
*/
|
||||||
|
public Tree<T> cloneTree() {
|
||||||
|
final Tree<T> result = ObjectUtil.clone(this);
|
||||||
|
result.setChildren(cloneChildren());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归复制子节点
|
||||||
|
*
|
||||||
|
* @return 新的子节点列表
|
||||||
|
*/
|
||||||
|
private List<Tree<T>> cloneChildren() {
|
||||||
|
final List<Tree<T>> children = getChildren();
|
||||||
|
if (null == children) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final List<Tree<T>> newChildren = new ArrayList<>(children.size());
|
||||||
|
children.forEach((t) -> newChildren.add(t.cloneTree()));
|
||||||
|
return newChildren;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打印
|
* 打印
|
||||||
*
|
*
|
||||||
|
@ -76,4 +76,48 @@ public class TreeTest {
|
|||||||
|
|
||||||
Assert .assertEquals(7, ids.size());
|
Assert .assertEquals(7, ids.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cloneTreeTest(){
|
||||||
|
final Tree<String> tree = TreeUtil.buildSingle(nodeList, "0");
|
||||||
|
final Tree<String> cloneTree = tree.cloneTree();
|
||||||
|
|
||||||
|
List<String> ids = new ArrayList<>();
|
||||||
|
cloneTree.walk((tr)-> ids.add(tr.getId()));
|
||||||
|
|
||||||
|
Assert .assertEquals(7, ids.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void filterTest(){
|
||||||
|
// 经过过滤,丢掉"用户添加"节点
|
||||||
|
final Tree<String> tree = TreeUtil.buildSingle(nodeList, "0");
|
||||||
|
tree.filter((t)->{
|
||||||
|
final CharSequence name = t.getName();
|
||||||
|
return null != name && name.toString().contains("管理");
|
||||||
|
});
|
||||||
|
|
||||||
|
List<String> ids = new ArrayList<>();
|
||||||
|
tree.walk((tr)-> ids.add(tr.getId()));
|
||||||
|
Assert .assertEquals(6, ids.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void filterNewTest(){
|
||||||
|
final Tree<String> tree = TreeUtil.buildSingle(nodeList, "0");
|
||||||
|
|
||||||
|
// 经过过滤,生成新的树
|
||||||
|
Tree<String> newTree = tree.filterNew((t)->{
|
||||||
|
final CharSequence name = t.getName();
|
||||||
|
return null != name && name.toString().contains("管理");
|
||||||
|
});
|
||||||
|
|
||||||
|
List<String> ids = new ArrayList<>();
|
||||||
|
newTree.walk((tr)-> ids.add(tr.getId()));
|
||||||
|
Assert .assertEquals(6, ids.size());
|
||||||
|
|
||||||
|
List<String> ids2 = new ArrayList<>();
|
||||||
|
tree.walk((tr)-> ids2.add(tr.getId()));
|
||||||
|
Assert .assertEquals(7, ids2.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,6 @@ public class TimingWheel {
|
|||||||
* @param consumer 任务处理器
|
* @param consumer 任务处理器
|
||||||
*/
|
*/
|
||||||
public TimingWheel(long tickMs, int wheelSize, long currentTime, Consumer<TimerTaskList> consumer) {
|
public TimingWheel(long tickMs, int wheelSize, long currentTime, Consumer<TimerTaskList> consumer) {
|
||||||
this.currentTime = currentTime;
|
|
||||||
this.tickMs = tickMs;
|
this.tickMs = tickMs;
|
||||||
this.wheelSize = wheelSize;
|
this.wheelSize = wheelSize;
|
||||||
this.interval = tickMs * wheelSize;
|
this.interval = tickMs * wheelSize;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user