- 最近在微信看到大牛整理的树形结构工具类,记录下备用。
- 在本地用并行计算替换创建数的方法,发现不管给ForkJoinPool设置多少线程数,结果总是比普通的for循环慢。且用到的java流计算越多,性能越差。本地测试最大到10000000。
package com.server.utils;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class TreeUtil {
public static void main(String[] args) {
int size = 1000000;
List<TreeNode> list = generateTestData(size);
long start = System.currentTimeMillis();
List<TreeNode> tree = makeTree(list,
TreeNode::getParentId,
TreeNode::getId,
x -> x.getParentId() == 0,
TreeNode::setChildren
);
System.out.println("耗时:" + (System.currentTimeMillis() - start));
}
private static List<TreeNode> generateTestData(int size) {
List<TreeNode> treeNodes = new ArrayList<>();
for (int i = 0; i < size; i++) {
treeNodes.add(new TreeNode(i + 1, i));
}
return treeNodes;
}
public static <T, E> List<E> makeTree(List<E> eList, Function<E, T> pIdGetter, Function<E, T> idGetter, Predicate<E> rootCheck, BiConsumer<E, List<E>> setSubChildren) {
Map<T, List<E>> parentMenuMap = new HashMap<>();
for (E node : eList) {
T parentId = pIdGetter.apply(node);
parentMenuMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(node);
}
List<E> result = new ArrayList<>();
for (E node : eList) {
setSubChildren.accept(node, parentMenuMap.getOrDefault(idGetter.apply(node), new ArrayList<>()));
if (rootCheck.test(node)) {
result.add(node);
}
}
return result;
}
public static <E> List<E> search(List<E> tree, Predicate<E> predicate, Function<E, List<E>> getSubChildren) {
List<E> result = new ArrayList<>();
for (E item : tree) {
List<E> childList = getSubChildren.apply(item);
List<E> filteredChildren = new ArrayList<>();
if (childList != null && !childList.isEmpty()) {
filteredChildren = search(childList, predicate, getSubChildren);
}
if (predicate.test(item) || !filteredChildren.isEmpty()) {
result.add(item);
if (!filteredChildren.isEmpty()) {
getSubChildren.apply(item).clear();
getSubChildren.apply(item).addAll(filteredChildren);
}
}
}
return result;
}
public static <E> List<E> filter(List<E> tree, Predicate<E> predicate, Function<E, List<E>> getChildren) {
return tree.stream().filter(item -> {
if (predicate.test(item)) {
List<E> children = getChildren.apply(item);
if (children != null && !children.isEmpty()) {
filter(children, predicate, getChildren);
}
return true;
}
return false;
}).collect(Collectors.toList());
}
public static <E> List<E> sort(List<E> tree, Comparator<? super E> comparator, Function<E, List<E>> getChildren) {
for (E item : tree) {
List<E> childList = getChildren.apply(item);
if (childList != null && !childList.isEmpty()) {
sort(childList, comparator, getChildren);
}
}
tree.sort(comparator);
return tree;
}
public static <E> List<E> filterAndHandler(List<E> tree, Predicate<E> predicate, Function<E, List<E>> getChildren, BiConsumer<E, Boolean> setChoose) {
return tree.stream().filter(item -> {
if (predicate.test(item)) {
setChoose.accept(item, true);
} else {
setChoose.accept(item, false);
}
List<E> children = getChildren.apply(item);
if (children != null && !children.isEmpty()) {
filterAndHandler(children, predicate, getChildren, setChoose);
}
return true;
}).collect(Collectors.toList());
}
}