mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
:trollface: 移除EasyStream中对于树的函数
This commit is contained in:
parent
3aac1e9af6
commit
e96eff5cff
@ -430,124 +430,6 @@ public class CollectorUtil {
|
||||
return toMap(Map.Entry::getKey, Map.Entry::getValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点
|
||||
* 因为需要在当前传入数据里查找,所以这是一个结束操作 <br>
|
||||
*
|
||||
* @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} 会过滤掉id为null的元素
|
||||
* @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId}
|
||||
* @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren}
|
||||
* @param isParallel 是否并行去组装,数据量特别大时使用
|
||||
* @param <T> 此处是元素类型
|
||||
* @param <R> 此处是id、parentId的泛型限制
|
||||
* @return list 组装好的树 <br>
|
||||
* eg:
|
||||
* <pre>{@code
|
||||
* List<Student> studentTree = students.stream().collect(toTree(Student::getId, Student::getParentId, Student::setChildren, isParallel));
|
||||
* }</pre>
|
||||
*/
|
||||
public static <R extends Comparable<R>, T> Collector<T, ?, List<T>> toTree(
|
||||
final Function<T, R> idGetter,
|
||||
final Function<T, R> pIdGetter,
|
||||
final BiConsumer<T, List<T>> childrenSetter,
|
||||
final boolean isParallel) {
|
||||
return toTree(idGetter, pIdGetter, null, childrenSetter, isParallel);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>将集合转换为树,默认用 {@code parentId == pidValue} 来判断树的根节点,可以为null
|
||||
* 因为需要在当前传入数据里查找,所以这是一个结束操作 <br>
|
||||
*
|
||||
* @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} 会过滤掉id为null的元素
|
||||
* @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId}
|
||||
* @param pidValue pid的值
|
||||
* @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren}
|
||||
* @param isParallel 是否并行去组装,数据量特别大时使用
|
||||
* @param <T> 此处是元素类型
|
||||
* @param <R> 此处是id、parentId的泛型限制
|
||||
* @return list 组装好的树 <br>
|
||||
* eg:
|
||||
* <pre>{@code
|
||||
* List<Student> studentTree = students.stream().collect(toTree(Student::getId, Student::getParentId, 0L, Student::setChildren, isParallel));
|
||||
* }</pre>
|
||||
* @author VampireAchao
|
||||
*/
|
||||
public static <R extends Comparable<R>, T> Collector<T, ?, List<T>> toTree(
|
||||
final Function<T, R> idGetter,
|
||||
final Function<T, R> pIdGetter,
|
||||
final R pidValue,
|
||||
final BiConsumer<T, List<T>> childrenSetter,
|
||||
final boolean isParallel) {
|
||||
return Collectors.collectingAndThen(filtering(e -> idGetter.apply(e) != null, groupingBy(pIdGetter, Collectors.toList())),
|
||||
getChildrenFromMapByPidAndSet(idGetter, pIdValuesMap -> pIdValuesMap.get(pidValue), childrenSetter, isParallel));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将集合转换为树,自定义根节点的判断条件
|
||||
* 因为需要在当前传入数据里查找,所以这是一个结束操作
|
||||
*
|
||||
* @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} 会过滤掉id为null的元素
|
||||
* @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId}
|
||||
* @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren}
|
||||
* @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) }
|
||||
* @param isParallel 是否并行处理
|
||||
* @param <T> 此处是元素类型
|
||||
* @param <R> 此处是id、parentId的泛型限制
|
||||
* @return list 组装好的树 <br>
|
||||
* eg:
|
||||
* <pre>{@code
|
||||
* List<Student> studentTree = EasyStream.of(students).
|
||||
* .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
|
||||
* }</pre>
|
||||
* @author VampireAchao
|
||||
*/
|
||||
public static <R extends Comparable<R>, T> Collector<T, ?, List<T>> toTree(
|
||||
final Function<T, R> idGetter,
|
||||
final Function<T, R> pIdGetter,
|
||||
final BiConsumer<T, List<T>> childrenSetter,
|
||||
final Predicate<T> parentPredicate,
|
||||
final boolean isParallel) {
|
||||
final List<T> parents = new ArrayList<>();
|
||||
return Collectors.collectingAndThen(filtering(e -> {
|
||||
if (parentPredicate.test(e)) {
|
||||
parents.add(e);
|
||||
}
|
||||
return idGetter.apply(e) != null;
|
||||
}, groupingBy(pIdGetter)),
|
||||
getChildrenFromMapByPidAndSet(idGetter, pIdValuesMap -> parents, childrenSetter, isParallel));
|
||||
}
|
||||
|
||||
/**
|
||||
* toTree的内联函数
|
||||
* 因为需要在当前传入数据里查找,所以这是一个结束操作
|
||||
*
|
||||
* @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId}
|
||||
* @param parentFactory 顶部数据工厂方法
|
||||
* @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren}
|
||||
* @param isParallel 是否并行处理
|
||||
* @param <T> 此处是元素类型
|
||||
* @param <R> 此处是id的泛型限制
|
||||
* @return list 组装好的树
|
||||
* @author VampireAchao
|
||||
*/
|
||||
private static <R extends Comparable<R>, T> Function<Map<R, List<T>>, List<T>> getChildrenFromMapByPidAndSet(
|
||||
final Function<T, R> idGetter,
|
||||
final Function<Map<R, List<T>>, List<T>> parentFactory,
|
||||
final BiConsumer<T, List<T>> childrenSetter,
|
||||
final boolean isParallel) {
|
||||
return pIdValuesMap -> {
|
||||
EasyStream.of(pIdValuesMap.values(), isParallel).flat(Function.identity())
|
||||
.forEach(value -> {
|
||||
final List<T> children = pIdValuesMap.get(idGetter.apply(value));
|
||||
if (children != null) {
|
||||
childrenSetter.accept(value, children);
|
||||
}
|
||||
});
|
||||
return parentFactory.apply(pIdValuesMap);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>过滤</p >
|
||||
*
|
||||
|
@ -205,83 +205,6 @@ public interface TerminableWrappedStream<T, S extends TerminableWrappedStream<T,
|
||||
return EasyStream.of(toList()).toMap(e -> index.incrementAndGet(), valueMapper, (l, r) -> r);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点
|
||||
* 因为需要在当前传入数据里查找,所以这是一个结束操作 <br>
|
||||
*
|
||||
* @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId}
|
||||
* @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId}
|
||||
* @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren}
|
||||
* @param <R> 此处是id、parentId的泛型限制
|
||||
* @return list 组装好的树 <br>
|
||||
* eg:
|
||||
* <pre>{@code
|
||||
* List<Student> studentTree = EasyStream.of(students).
|
||||
* toTree(Student::getId, Student::getParentId, Student::setChildren);
|
||||
* }</pre>
|
||||
* @author VampireAchao
|
||||
*/
|
||||
default <R extends Comparable<R>> List<T> toTree(
|
||||
final Function<T, R> idGetter,
|
||||
final Function<T, R> pIdGetter,
|
||||
final BiConsumer<T, List<T>> childrenSetter) {
|
||||
return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, isParallel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>将集合转换为树,传入 {@code parentId == pidValue} 来判断树的根节点
|
||||
* 因为需要在当前传入数据里查找,所以这是一个结束操作 <br>
|
||||
*
|
||||
* @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId}
|
||||
* @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId}
|
||||
* @param pIdValue parentId的值,支持 {@code null}
|
||||
* @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren}
|
||||
* @param <R> 此处是id、parentId的泛型限制
|
||||
* @return list 组装好的树 <br>
|
||||
* eg:
|
||||
* <pre>{@code
|
||||
* List<Student> studentTree = EasyStream.of(students).
|
||||
* toTree(Student::getId, Student::getParentId, 0L, Student::setChildren);
|
||||
* }</pre>
|
||||
* @author VampireAchao
|
||||
*/
|
||||
default <R extends Comparable<R>> List<T> toTree(
|
||||
final Function<T, R> idGetter,
|
||||
final Function<T, R> pIdGetter,
|
||||
final R pIdValue,
|
||||
final BiConsumer<T, List<T>> childrenSetter) {
|
||||
return collect(CollectorUtil.toTree(idGetter, pIdGetter, pIdValue, childrenSetter, isParallel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将集合转换为树,自定义根节点的判断条件
|
||||
* 因为需要在当前传入数据里查找,所以这是一个结束操作
|
||||
*
|
||||
* @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId}
|
||||
* @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId}
|
||||
* @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren}
|
||||
* @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) }
|
||||
* @param <R> 此处是id、parentId的泛型限制
|
||||
* @return list 组装好的树 <br>
|
||||
* eg:
|
||||
* <pre>{@code
|
||||
* List<Student> studentTree = EasyStream.of(students).
|
||||
* .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
|
||||
* }</pre>
|
||||
* @author VampireAchao
|
||||
*/
|
||||
default <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) {
|
||||
return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, parentPredicate, isParallel()));
|
||||
}
|
||||
|
||||
|
||||
// endregion
|
||||
|
||||
// region ============ to zip ============
|
||||
|
||||
/**
|
||||
|
@ -2,19 +2,14 @@ package cn.hutool.core.stream;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Tolerate;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
/**
|
||||
@ -436,124 +431,4 @@ public class EasyStreamTest {
|
||||
Assert.assertTrue(EasyStream.of(1).isNotEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToTree() {
|
||||
Consumer<Object> test = o -> {
|
||||
final List<Student> studentTree = EasyStream
|
||||
.of(
|
||||
Student.builder().id(1L).name("dromara").build(),
|
||||
Student.builder().id(2L).name("baomidou").build(),
|
||||
Student.builder().id(3L).name("hutool").parentId(1L).build(),
|
||||
Student.builder().id(4L).name("sa-token").parentId(1L).build(),
|
||||
Student.builder().id(5L).name("mybatis-plus").parentId(2L).build(),
|
||||
Student.builder().id(6L).name("looly").parentId(3L).build(),
|
||||
Student.builder().id(7L).name("click33").parentId(4L).build(),
|
||||
Student.builder().id(8L).name("jobob").parentId(5L).build()
|
||||
)
|
||||
// just 3 lambda,top parentId is null
|
||||
.toTree(Student::getId, Student::getParentId, Student::setChildren);
|
||||
Assert.assertEquals(asList(
|
||||
Student.builder().id(1L).name("dromara")
|
||||
.children(asList(Student.builder().id(3L).name("hutool").parentId(1L)
|
||||
.children(singletonList(Student.builder().id(6L).name("looly").parentId(3L).build()))
|
||||
.build(),
|
||||
Student.builder().id(4L).name("sa-token").parentId(1L)
|
||||
.children(singletonList(Student.builder().id(7L).name("click33").parentId(4L).build()))
|
||||
.build()))
|
||||
.build(),
|
||||
Student.builder().id(2L).name("baomidou")
|
||||
.children(singletonList(
|
||||
Student.builder().id(5L).name("mybatis-plus").parentId(2L)
|
||||
.children(singletonList(
|
||||
Student.builder().id(8L).name("jobob").parentId(5L).build()
|
||||
))
|
||||
.build()))
|
||||
.build()
|
||||
), studentTree);
|
||||
};
|
||||
test = test.andThen(o -> {
|
||||
final List<Student> studentTree = EasyStream
|
||||
.of(
|
||||
Student.builder().id(1L).name("dromara").matchParent(true).build(),
|
||||
Student.builder().id(2L).name("baomidou").matchParent(true).build(),
|
||||
Student.builder().id(3L).name("hutool").parentId(1L).build(),
|
||||
Student.builder().id(4L).name("sa-token").parentId(1L).build(),
|
||||
Student.builder().id(5L).name("mybatis-plus").parentId(2L).build(),
|
||||
Student.builder().id(6L).name("looly").parentId(3L).build(),
|
||||
Student.builder().id(7L).name("click33").parentId(4L).build(),
|
||||
Student.builder().id(8L).name("jobob").parentId(5L).build()
|
||||
)
|
||||
// just 4 lambda ,top by condition
|
||||
.toTree(Student::getId, Student::getParentId, Student::setChildren, s -> BooleanUtil.isTrue(s.getMatchParent()));
|
||||
Assert.assertEquals(asList(
|
||||
Student.builder().id(1L).name("dromara").matchParent(true)
|
||||
.children(asList(Student.builder().id(3L).name("hutool").parentId(1L)
|
||||
.children(singletonList(Student.builder().id(6L).name("looly").parentId(3L).build()))
|
||||
.build(),
|
||||
Student.builder().id(4L).name("sa-token").parentId(1L)
|
||||
.children(singletonList(Student.builder().id(7L).name("click33").parentId(4L).build()))
|
||||
.build()))
|
||||
.build(),
|
||||
Student.builder().id(2L).name("baomidou").matchParent(true)
|
||||
.children(singletonList(
|
||||
Student.builder().id(5L).name("mybatis-plus").parentId(2L)
|
||||
.children(singletonList(
|
||||
Student.builder().id(8L).name("jobob").parentId(5L).build()
|
||||
))
|
||||
.build()))
|
||||
.build()
|
||||
), studentTree);
|
||||
});
|
||||
test.accept(new Object());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlatTree() {
|
||||
final List<Student> studentTree = asList(
|
||||
Student.builder().id(1L).name("dromara")
|
||||
.children(asList(Student.builder().id(3L).name("hutool").parentId(1L)
|
||||
.children(singletonList(Student.builder().id(6L).name("looly").parentId(3L).build()))
|
||||
.build(),
|
||||
Student.builder().id(4L).name("sa-token").parentId(1L)
|
||||
.children(singletonList(Student.builder().id(7L).name("click33").parentId(4L).build()))
|
||||
.build()))
|
||||
.build(),
|
||||
Student.builder().id(2L).name("baomidou")
|
||||
.children(singletonList(
|
||||
Student.builder().id(5L).name("mybatis-plus").parentId(2L)
|
||||
.children(singletonList(
|
||||
Student.builder().id(8L).name("jobob").parentId(5L).build()
|
||||
))
|
||||
.build()))
|
||||
.build()
|
||||
);
|
||||
Assert.assertEquals(asList(
|
||||
Student.builder().id(1L).name("dromara").build(),
|
||||
Student.builder().id(2L).name("baomidou").build(),
|
||||
Student.builder().id(3L).name("hutool").parentId(1L).build(),
|
||||
Student.builder().id(4L).name("sa-token").parentId(1L).build(),
|
||||
Student.builder().id(5L).name("mybatis-plus").parentId(2L).build(),
|
||||
Student.builder().id(6L).name("looly").parentId(3L).build(),
|
||||
Student.builder().id(7L).name("click33").parentId(4L).build(),
|
||||
Student.builder().id(8L).name("jobob").parentId(5L).build()
|
||||
), EasyStream.of(studentTree).flatTree(Student::getChildren, Student::setChildren).sorted(Comparator.comparingLong(Student::getId)).toList());
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
@lombok.Builder
|
||||
public static class Student {
|
||||
private String name;
|
||||
private Integer age;
|
||||
private Long id;
|
||||
private Long parentId;
|
||||
private List<Student> children;
|
||||
private Boolean matchParent;
|
||||
|
||||
@Tolerate
|
||||
public Student() {
|
||||
// this is an accessible parameterless constructor.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user