优化toTree方法的实现,使用循环代替递归;

This commit is contained in:
emptypoint 2022-09-18 20:54:33 +08:00
parent 9417bbee2e
commit 28f6a76933

View File

@ -1,7 +1,7 @@
package cn.hutool.core.stream;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
@ -267,7 +267,7 @@ public class EasyStream<T> extends AbstractEnhancedWrappedStream<T, EasyStream<T
}
/**
* <p>将集合转换为树默认用 {@code parentId == null} 作为顶部内置一个小递归
* <p>将集合转换为树默认用 {@code parentId == null} 来判断树的根节点
* 因为需要在当前传入数据里查找所以这是一个结束操作 <br>
*
* @param idGetter id的getter对应的lambda可以写作 {@code Student::getId}
@ -285,12 +285,13 @@ public class EasyStream<T> extends AbstractEnhancedWrappedStream<T, EasyStream<T
final Function<T, R> idGetter,
final Function<T, R> pIdGetter,
final BiConsumer<T, List<T>> childrenSetter) {
final Map<R, List<T>> pIdValuesMap = group(pIdGetter);
return getChildrenFromMapByPidAndSet(idGetter, childrenSetter, pIdValuesMap, pIdValuesMap.get(null));
// 使用 parentId == null 判断是否为根节点
final Predicate<T> parentPredicate = node -> null == pIdGetter.apply(node);
return toTree(idGetter, pIdGetter, childrenSetter, parentPredicate);
}
/**
* 将集合转换为树自定义树顶部的判断条件内置一个小递归(没错lambda可以写递归)
* 将集合转换为树自定义根节点的判断条件
* 因为需要在当前传入数据里查找所以这是一个结束操作
*
* @param idGetter id的getter对应的lambda可以写作 {@code Student::getId}
@ -305,46 +306,31 @@ public class EasyStream<T> extends AbstractEnhancedWrappedStream<T, EasyStream<T
* .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
* }</pre>
*/
public <R extends Comparable<R>> List<T> toTree(
final Function<T, R> idGetter,
final Function<T, R> pIdGetter,
final BiConsumer<T, List<T>> childrenSetter,
final Predicate<T> parentPredicate) {
Objects.requireNonNull(parentPredicate);
final List<T> list = toList();
// 根节点列表
final List<T> parents = EasyStream.of(list).filter(parentPredicate).toList();
return getChildrenFromMapByPidAndSet(idGetter, childrenSetter, EasyStream.of(list).group(pIdGetter), parents);
}
/**
* toTree的内联函数内置一个小递归(没错lambda可以写递归)
* 因为需要在当前传入数据里查找所以这是一个结束操作
*
* @param idGetter id的getter对应的lambda可以写作 {@code Student::getId}
* @param childrenSetter children的setter对应的lambda可以写作 {@code Student::setChildren}
* @param pIdValuesMap parentId和值组成的map用来降低复杂度
* @param parents 顶部数据
* @param <R> 此处是id的泛型限制
* @return list 组装好的树
*/
private <R extends Comparable<R>> List<T> getChildrenFromMapByPidAndSet(
final Function<T, R> idGetter,
final BiConsumer<T, List<T>> childrenSetter,
final Map<R, List<T>> pIdValuesMap,
final List<T> parents) {
Objects.requireNonNull(idGetter);
Objects.requireNonNull(pIdGetter);
Objects.requireNonNull(childrenSetter);
Objects.requireNonNull(pIdValuesMap);
final MutableObj<Consumer<List<T>>> recursiveRef = new MutableObj<>();
final Consumer<List<T>> recursive = values -> EasyStream.of(values, isParallel()).forEach(value -> {
final List<T> children = pIdValuesMap.get(idGetter.apply(value));
childrenSetter.accept(value, children);
recursiveRef.get().accept(children);
});
recursiveRef.set(recursive);
recursive.accept(parents);
Objects.requireNonNull(parentPredicate);
List<T> nodeList = toList();
// 父id 关联的 子节点列表
final Map<R, List<T>> pId2ChildrenMap = of(nodeList).group(pIdGetter);
List<T> parents = ListUtil.of();
for (T node : nodeList) {
if (parentPredicate.test(node)) {
parents.add(node);
}
// 设置 该节点的子节点列表
final List<T> children = pId2ChildrenMap.get(idGetter.apply(node));
if (children != null) {
childrenSetter.accept(node, children);
}
}
return parents;
}