mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
!808 EasyStream.toTree移除对predicate.test的返回结果为null的支持
Merge pull request !808 from emptypoint/EasyStream-issue
This commit is contained in:
commit
d8bcf027f7
@ -5,10 +5,7 @@ import cn.hutool.core.text.StrUtil;
|
|||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.*;
|
||||||
import java.util.function.BinaryOperator;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.stream.Collector;
|
import java.util.stream.Collector;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -371,4 +368,131 @@ public class CollectorUtil {
|
|||||||
public static <K, V> Collector<Map.Entry<K, V>, ?, Map<K, V>> entryToMap() {
|
public static <K, V> Collector<Map.Entry<K, V>, ?, Map<K, V>> entryToMap() {
|
||||||
return toMap(Map.Entry::getKey, Map.Entry::getValue);
|
return toMap(Map.Entry::getKey, Map.Entry::getValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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 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}
|
||||||
|
* @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(groupingBy(pIdGetter, Collectors.toList()),
|
||||||
|
getChildrenFromMapByPidAndSet(idGetter, pIdValuesMap -> pIdValuesMap.get(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 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(groupingBy(pIdGetter,
|
||||||
|
new SimpleCollector<>(ArrayList::new,
|
||||||
|
(acc, e) -> {
|
||||||
|
if (parentPredicate.test(e)) {
|
||||||
|
parents.add(e);
|
||||||
|
}
|
||||||
|
if (idGetter.apply(e) != null) {
|
||||||
|
acc.add(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(left, right) -> {
|
||||||
|
left.addAll(right);
|
||||||
|
return left;
|
||||||
|
},
|
||||||
|
CH_ID)),
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
package cn.hutool.core.stream;
|
package cn.hutool.core.stream;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Opt;
|
import cn.hutool.core.lang.Opt;
|
||||||
import cn.hutool.core.lang.mutable.MutableObj;
|
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
@ -266,91 +264,6 @@ public class EasyStream<T> extends AbstractEnhancedWrappedStream<T, EasyStream<T
|
|||||||
return new EasyStream<>(stream);
|
return new EasyStream<>(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <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>
|
|
||||||
*/
|
|
||||||
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 Map<R, List<T>> pIdValuesMap = group(pIdGetter);
|
|
||||||
return getChildrenFromMapByPidAndSet(idGetter, childrenSetter, pIdValuesMap, pIdValuesMap.get(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将集合转换为树,自定义树顶部的判断条件,内置一个小递归(没错,lambda可以写递归)
|
|
||||||
* 因为需要在当前传入数据里查找,所以这是一个结束操作
|
|
||||||
*
|
|
||||||
* @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>
|
|
||||||
*/
|
|
||||||
|
|
||||||
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(e ->
|
|
||||||
// 此处是为了适配 parentPredicate.test空指针 情况
|
|
||||||
// 因为Predicate.test的返回值是boolean,所以如果 e -> null 这种返回null的情况,会直接抛出NPE
|
|
||||||
Opt.ofTry(() -> parentPredicate.test(e)).filter(Boolean::booleanValue).isPresent())
|
|
||||||
.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(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);
|
|
||||||
return parents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 建造者
|
* 建造者
|
||||||
*
|
*
|
||||||
|
@ -22,47 +22,47 @@ import java.util.stream.Stream;
|
|||||||
*/
|
*/
|
||||||
public interface TerminableWrappedStream<T, S extends TerminableWrappedStream<T, S>> extends WrappedStream<T, S> {
|
public interface TerminableWrappedStream<T, S extends TerminableWrappedStream<T, S>> extends WrappedStream<T, S> {
|
||||||
|
|
||||||
// region ============ to collection ============
|
// region ============ to collection ============
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为{@link ArrayList}
|
* 转换为{@link ArrayList}
|
||||||
*
|
*
|
||||||
* @return 集合
|
* @return 集合
|
||||||
* @see #toColl(Supplier)
|
|
||||||
*/
|
|
||||||
default List<T> toList() {
|
|
||||||
return this.toColl(ArrayList::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 换为不可变集合
|
|
||||||
*
|
|
||||||
* @return 集合
|
|
||||||
* @see #toColl(Supplier)
|
* @see #toColl(Supplier)
|
||||||
*/
|
*/
|
||||||
default List<T> toUnmodifiableList() {
|
default List<T> toList() {
|
||||||
return Collections.unmodifiableList(this.toList());
|
return this.toColl(ArrayList::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为HashSet
|
* 换为不可变集合
|
||||||
*
|
*
|
||||||
* @return 集合
|
* @return 集合
|
||||||
* @see #toColl(Supplier)
|
* @see #toColl(Supplier)
|
||||||
*/
|
*/
|
||||||
default Set<T> toSet() {
|
default List<T> toUnmodifiableList() {
|
||||||
return this.toColl(HashSet::new);
|
return Collections.unmodifiableList(this.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 换为不可变集合
|
* 转换为HashSet
|
||||||
*
|
*
|
||||||
* @return 集合
|
* @return 集合
|
||||||
* @see #toColl(Supplier)
|
* @see #toColl(Supplier)
|
||||||
*/
|
*/
|
||||||
default Set<T> toUnmodifiableSet() {
|
default Set<T> toSet() {
|
||||||
return Collections.unmodifiableSet(this.toSet());
|
return this.toColl(HashSet::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 换为不可变集合
|
||||||
|
*
|
||||||
|
* @return 集合
|
||||||
|
* @see #toColl(Supplier)
|
||||||
|
*/
|
||||||
|
default Set<T> toUnmodifiableSet() {
|
||||||
|
return Collections.unmodifiableSet(this.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换成集合
|
* 转换成集合
|
||||||
@ -76,103 +76,103 @@ public interface TerminableWrappedStream<T, S extends TerminableWrappedStream<T,
|
|||||||
return unwrap().collect(Collectors.toCollection(collectionFactory));
|
return unwrap().collect(Collectors.toCollection(collectionFactory));
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region ============ to map ============
|
// region ============ to map ============
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为map,key为给定操作执行后的返回值,value为当前元素
|
* 转换为map,key为给定操作执行后的返回值,value为当前元素
|
||||||
*
|
*
|
||||||
* @param keyMapper 指定的key操作
|
* @param keyMapper 指定的key操作
|
||||||
* @param <K> key类型
|
* @param <K> key类型
|
||||||
* @return map
|
* @return map
|
||||||
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
||||||
*/
|
*/
|
||||||
default <K> Map<K, T> toMap(final Function<? super T, ? extends K> keyMapper) {
|
default <K> Map<K, T> toMap(final Function<? super T, ? extends K> keyMapper) {
|
||||||
return this.toMap(keyMapper, Function.identity());
|
return this.toMap(keyMapper, Function.identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为map,key,value为给定操作执行后的返回值
|
* 转换为map,key,value为给定操作执行后的返回值
|
||||||
*
|
*
|
||||||
* @param keyMapper 指定的key操作
|
* @param keyMapper 指定的key操作
|
||||||
* @param valueMapper 指定value操作
|
* @param valueMapper 指定value操作
|
||||||
* @param <K> key类型
|
* @param <K> key类型
|
||||||
* @param <U> value类型
|
* @param <U> value类型
|
||||||
* @return map
|
* @return map
|
||||||
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
||||||
*/
|
*/
|
||||||
default <K, U> Map<K, U> toMap(
|
default <K, U> Map<K, U> toMap(
|
||||||
final Function<? super T, ? extends K> keyMapper, final Function<? super T, ? extends U> valueMapper) {
|
final Function<? super T, ? extends K> keyMapper, final Function<? super T, ? extends U> valueMapper) {
|
||||||
return this.toMap(keyMapper, valueMapper, (l, r) -> r);
|
return this.toMap(keyMapper, valueMapper, (l, r) -> r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为不可变map,key,value为给定操作执行后的返回值
|
* 转换为不可变map,key,value为给定操作执行后的返回值
|
||||||
*
|
*
|
||||||
* @param keyMapper 指定的key操作
|
* @param keyMapper 指定的key操作
|
||||||
* @param valueMapper 指定value操作
|
* @param valueMapper 指定value操作
|
||||||
* @param <K> key类型
|
* @param <K> key类型
|
||||||
* @param <U> value类型
|
* @param <U> value类型
|
||||||
* @return map
|
* @return map
|
||||||
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
||||||
*/
|
*/
|
||||||
default <K, U> Map<K, U> toUnmodifiableMap(
|
default <K, U> Map<K, U> toUnmodifiableMap(
|
||||||
final Function<? super T, ? extends K> keyMapper, final Function<? super T, ? extends U> valueMapper) {
|
final Function<? super T, ? extends K> keyMapper, final Function<? super T, ? extends U> valueMapper) {
|
||||||
return Collections.unmodifiableMap(this.toMap(keyMapper, valueMapper));
|
return Collections.unmodifiableMap(this.toMap(keyMapper, valueMapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为map,key,value为给定操作执行后的返回值
|
* 转换为map,key,value为给定操作执行后的返回值
|
||||||
*
|
*
|
||||||
* @param keyMapper 指定的key操作
|
* @param keyMapper 指定的key操作
|
||||||
* @param valueMapper 指定value操作
|
* @param valueMapper 指定value操作
|
||||||
* @param mergeFunction 合并操作
|
* @param mergeFunction 合并操作
|
||||||
* @param <K> key类型
|
* @param <K> key类型
|
||||||
* @param <U> value类型
|
* @param <U> value类型
|
||||||
* @return map
|
* @return map
|
||||||
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
||||||
*/
|
*/
|
||||||
default <K, U> Map<K, U> toMap(
|
default <K, U> Map<K, U> toMap(
|
||||||
final Function<? super T, ? extends K> keyMapper,
|
final Function<? super T, ? extends K> keyMapper,
|
||||||
final Function<? super T, ? extends U> valueMapper,
|
final Function<? super T, ? extends U> valueMapper,
|
||||||
final BinaryOperator<U> mergeFunction) {
|
final BinaryOperator<U> mergeFunction) {
|
||||||
return this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
|
return this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为不可变map,key,value为给定操作执行后的返回值
|
* 转换为不可变map,key,value为给定操作执行后的返回值
|
||||||
*
|
*
|
||||||
* @param keyMapper 指定的key操作
|
* @param keyMapper 指定的key操作
|
||||||
* @param valueMapper 指定value操作
|
* @param valueMapper 指定value操作
|
||||||
* @param mergeFunction 合并操作
|
* @param mergeFunction 合并操作
|
||||||
* @param <K> key类型
|
* @param <K> key类型
|
||||||
* @param <U> value类型
|
* @param <U> value类型
|
||||||
* @return map
|
* @return map
|
||||||
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
* @see #toMap(Function, Function, BinaryOperator, Supplier)
|
||||||
*/
|
*/
|
||||||
default <K, U> Map<K, U> toUnmodifiableMap(
|
default <K, U> Map<K, U> toUnmodifiableMap(
|
||||||
final Function<? super T, ? extends K> keyMapper,
|
final Function<? super T, ? extends K> keyMapper,
|
||||||
final Function<? super T, ? extends U> valueMapper,
|
final Function<? super T, ? extends U> valueMapper,
|
||||||
final BinaryOperator<U> mergeFunction) {
|
final BinaryOperator<U> mergeFunction) {
|
||||||
return Collections.unmodifiableMap(
|
return Collections.unmodifiableMap(
|
||||||
this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new)
|
this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为map,key,value为给定操作执行后的返回值
|
* 转换为map,key,value为给定操作执行后的返回值
|
||||||
*
|
*
|
||||||
* @param keyMapper 指定的key操作
|
* @param keyMapper 指定的key操作
|
||||||
* @param valueMapper 指定value操作
|
* @param valueMapper 指定value操作
|
||||||
* @param mergeFunction 合并操作
|
* @param mergeFunction 合并操作
|
||||||
* @param mapSupplier map工厂
|
* @param mapSupplier map工厂
|
||||||
* @param <K> key类型
|
* @param <K> key类型
|
||||||
* @param <U> value类型
|
* @param <U> value类型
|
||||||
* @param <M> map类型
|
* @param <M> map类型
|
||||||
* @return map
|
* @return map
|
||||||
*/
|
*/
|
||||||
default <K, U, M extends Map<K, U>> M toMap(
|
default <K, U, M extends Map<K, U>> M toMap(
|
||||||
final Function<? super T, ? extends K> keyMapper,
|
final Function<? super T, ? extends K> keyMapper,
|
||||||
final Function<? super T, ? extends U> valueMapper,
|
final Function<? super T, ? extends U> valueMapper,
|
||||||
final BinaryOperator<U> mergeFunction,
|
final BinaryOperator<U> mergeFunction,
|
||||||
@ -181,40 +181,89 @@ public interface TerminableWrappedStream<T, S extends TerminableWrappedStream<T,
|
|||||||
Objects.requireNonNull(valueMapper);
|
Objects.requireNonNull(valueMapper);
|
||||||
Objects.requireNonNull(mergeFunction);
|
Objects.requireNonNull(mergeFunction);
|
||||||
Objects.requireNonNull(mapSupplier);
|
Objects.requireNonNull(mapSupplier);
|
||||||
return unwrap().collect(Collectors.toMap(keyMapper, valueMapper, mergeFunction, mapSupplier));
|
return unwrap().collect(Collectors.toMap(keyMapper, valueMapper, mergeFunction, mapSupplier));
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
/**
|
||||||
|
* <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()));
|
||||||
|
}
|
||||||
|
|
||||||
// region ============ to zip ============
|
/**
|
||||||
|
* 将集合转换为树,自定义根节点的判断条件
|
||||||
|
* 因为需要在当前传入数据里查找,所以这是一个结束操作
|
||||||
|
*
|
||||||
|
* @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()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 与给定的可迭代对象转换成map,key为现有元素,value为给定可迭代对象迭代的元素<br>
|
// endregion
|
||||||
* 至少包含全部的key,如果对应位置上的value不存在,则为null
|
|
||||||
*
|
// region ============ to zip ============
|
||||||
* @param other 可迭代对象
|
|
||||||
* @param <R> 可迭代对象迭代的元素类型
|
/**
|
||||||
* @return map,key为现有元素,value为给定可迭代对象迭代的元素;<br>
|
* 与给定的可迭代对象转换成map,key为现有元素,value为给定可迭代对象迭代的元素<br>
|
||||||
* 至少包含全部的key,如果对应位置上的value不存在,则为null;<br>
|
* 至少包含全部的key,如果对应位置上的value不存在,则为null
|
||||||
* 如果key重复, 则保留最后一个关联的value;<br>
|
*
|
||||||
*/
|
* @param other 可迭代对象
|
||||||
default <R> Map<T, R> toZip(final Iterable<R> other) {
|
* @param <R> 可迭代对象迭代的元素类型
|
||||||
|
* @return map,key为现有元素,value为给定可迭代对象迭代的元素;<br>
|
||||||
|
* 至少包含全部的key,如果对应位置上的value不存在,则为null;<br>
|
||||||
|
* 如果key重复, 则保留最后一个关联的value;<br>
|
||||||
|
*/
|
||||||
|
default <R> Map<T, R> toZip(final Iterable<R> other) {
|
||||||
Objects.requireNonNull(other);
|
Objects.requireNonNull(other);
|
||||||
// value对象迭代器
|
// value对象迭代器
|
||||||
final Iterator<R> iterator = Opt.ofNullable(other).map(Iterable::iterator).orElseGet(Collections::emptyIterator);
|
final Iterator<R> iterator = Opt.ofNullable(other).map(Iterable::iterator).orElseGet(Collections::emptyIterator);
|
||||||
if (this.isParallel()) {
|
if (this.isParallel()) {
|
||||||
final List<T> keyList = toList();
|
final List<T> keyList = toList();
|
||||||
final Map<T, R> map = new HashMap<>(keyList.size());
|
final Map<T, R> map = new HashMap<>(keyList.size());
|
||||||
for (final T key : keyList) {
|
for (final T key : keyList) {
|
||||||
map.put(key, iterator.hasNext() ? iterator.next() : null);
|
map.put(key, iterator.hasNext() ? iterator.next() : null);
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
} else {
|
} else {
|
||||||
return this.toMap(Function.identity(), e -> iterator.hasNext() ? iterator.next() : null);
|
return this.toMap(Function.identity(), e -> iterator.hasNext() ? iterator.next() : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region ============ to optional ============
|
// region ============ to optional ============
|
||||||
|
|
||||||
@ -408,7 +457,7 @@ public interface TerminableWrappedStream<T, S extends TerminableWrappedStream<T,
|
|||||||
* @see #group(Function, Supplier, Collector)
|
* @see #group(Function, Supplier, Collector)
|
||||||
*/
|
*/
|
||||||
default <K, A, D> Map<K, D> group(
|
default <K, A, D> Map<K, D> group(
|
||||||
final Function<? super T, ? extends K> classifier, final Collector<? super T, A, D> downstream) {
|
final Function<? super T, ? extends K> classifier, final Collector<? super T, A, D> downstream) {
|
||||||
return this.group(classifier, HashMap::new, downstream);
|
return this.group(classifier, HashMap::new, downstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,9 +475,9 @@ public interface TerminableWrappedStream<T, S extends TerminableWrappedStream<T,
|
|||||||
* @see CollectorUtil#groupingBy(Function, Supplier, Collector)
|
* @see CollectorUtil#groupingBy(Function, Supplier, Collector)
|
||||||
*/
|
*/
|
||||||
default <K, D, A, M extends Map<K, D>> M group(
|
default <K, D, A, M extends Map<K, D>> M group(
|
||||||
final Function<? super T, ? extends K> classifier,
|
final Function<? super T, ? extends K> classifier,
|
||||||
final Supplier<M> mapFactory,
|
final Supplier<M> mapFactory,
|
||||||
final Collector<? super T, A, D> downstream) {
|
final Collector<? super T, A, D> downstream) {
|
||||||
Objects.requireNonNull(classifier);
|
Objects.requireNonNull(classifier);
|
||||||
Objects.requireNonNull(mapFactory);
|
Objects.requireNonNull(mapFactory);
|
||||||
Objects.requireNonNull(downstream);
|
Objects.requireNonNull(downstream);
|
||||||
@ -449,8 +498,8 @@ public interface TerminableWrappedStream<T, S extends TerminableWrappedStream<T,
|
|||||||
/**
|
/**
|
||||||
* 根据给定判断条件分组
|
* 根据给定判断条件分组
|
||||||
*
|
*
|
||||||
* @param <C> 值类型
|
* @param <C> 值类型
|
||||||
* @param predicate 判断条件
|
* @param predicate 判断条件
|
||||||
* @param collFactory 提供的集合
|
* @param collFactory 提供的集合
|
||||||
* @return map
|
* @return map
|
||||||
* @see #partition(Predicate, Collector)
|
* @see #partition(Predicate, Collector)
|
||||||
@ -464,7 +513,7 @@ public interface TerminableWrappedStream<T, S extends TerminableWrappedStream<T,
|
|||||||
*
|
*
|
||||||
* @param predicate 判断条件
|
* @param predicate 判断条件
|
||||||
* @param downstream 下游操作
|
* @param downstream 下游操作
|
||||||
* @param <R> 返回值类型
|
* @param <R> 返回值类型
|
||||||
* @return map
|
* @return map
|
||||||
*/
|
*/
|
||||||
default <R> Map<Boolean, R> partition(final Predicate<T> predicate, final Collector<T, ?, R> downstream) {
|
default <R> Map<Boolean, R> partition(final Predicate<T> predicate, final Collector<T, ?, R> downstream) {
|
||||||
|
@ -40,7 +40,7 @@ public class AbstractEnhancedWrappedStreamTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testToSet() {
|
public void testToSet() {
|
||||||
final List<Integer> list = asList(1, 2, 3);
|
final List<Integer> list = asList(1, 2, 3);
|
||||||
Set<String> toSet = wrap(list).map(String::valueOf).toSet();
|
final Set<String> toSet = wrap(list).map(String::valueOf).toSet();
|
||||||
Assert.assertEquals(new HashSet<>(asList("1", "2", "3")), toSet);
|
Assert.assertEquals(new HashSet<>(asList("1", "2", "3")), toSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,7 +636,7 @@ public class AbstractEnhancedWrappedStreamTest {
|
|||||||
List<String> zip = wrap(orders).zip(list, (e1, e2) -> e1 + "." + e2).toList();
|
List<String> zip = wrap(orders).zip(list, (e1, e2) -> e1 + "." + e2).toList();
|
||||||
Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip);
|
Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip);
|
||||||
|
|
||||||
zip = wrap((Stream<? extends Object>) EasyStream.iterate(1, i -> i + 1)).limit(10).zip(list, (e1, e2) -> e1 + "." + e2).toList();
|
zip = this.wrap((Stream<Integer>)EasyStream.iterate(1, i -> i + 1)).limit(10).zip(list, (e1, e2) -> e1 + "." + e2).toList();
|
||||||
Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip);
|
Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,15 +663,15 @@ public class AbstractEnhancedWrappedStreamTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
private static <T> Wrapper<T> wrap(T... array) {
|
private final <T> Wrapper<T> wrap(final T... array) {
|
||||||
return new Wrapper<>(Stream.of(array));
|
return new Wrapper<>(Stream.of(array));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> Wrapper<T> wrap(Iterable<T> iterable) {
|
private <T> Wrapper<T> wrap(final Iterable<T> iterable) {
|
||||||
return new Wrapper<>(StreamSupport.stream(iterable.spliterator(), false));
|
return new Wrapper<>(StreamSupport.stream(iterable.spliterator(), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> Wrapper<T> wrap(Stream<T> stream) {
|
private <T> Wrapper<T> wrap(final Stream<T> stream) {
|
||||||
return new Wrapper<>(stream);
|
return new Wrapper<>(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,12 +683,12 @@ public class AbstractEnhancedWrappedStreamTest {
|
|||||||
* @param stream 包装的流对象
|
* @param stream 包装的流对象
|
||||||
* @throws NullPointerException 当{@code unwrap}为{@code null}时抛出
|
* @throws NullPointerException 当{@code unwrap}为{@code null}时抛出
|
||||||
*/
|
*/
|
||||||
protected Wrapper(Stream<T> stream) {
|
protected Wrapper(final Stream<T> stream) {
|
||||||
super(stream);
|
super(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Wrapper<T> wrap(Stream<T> source) {
|
public Wrapper<T> wrap(final Stream<T> source) {
|
||||||
return new Wrapper<>(source);
|
return new Wrapper<>(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package cn.hutool.core.stream;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.ListUtil;
|
import cn.hutool.core.collection.ListUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.BooleanUtil;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Tolerate;
|
import lombok.experimental.Tolerate;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@ -181,7 +182,7 @@ public class EasyStreamTest {
|
|||||||
Assert.assertEquals(collect2, distinctBy2);
|
Assert.assertEquals(collect2, distinctBy2);
|
||||||
|
|
||||||
Assert.assertEquals(
|
Assert.assertEquals(
|
||||||
4, EasyStream.of(1, 2, 2, null, 3, null).parallel(true).distinct(t -> Objects.isNull(t) ? null : t.toString()).sequential().count()
|
4, EasyStream.of(1, 2, 2, null, 3, null).parallel(true).distinct(t -> Objects.isNull(t) ? null : t.toString()).sequential().count()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +477,7 @@ public class EasyStreamTest {
|
|||||||
Student.builder().id(8L).name("jobob").parentId(5L).build()
|
Student.builder().id(8L).name("jobob").parentId(5L).build()
|
||||||
)
|
)
|
||||||
// just 4 lambda ,top by condition
|
// just 4 lambda ,top by condition
|
||||||
.toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
|
.toTree(Student::getId, Student::getParentId, Student::setChildren, s -> BooleanUtil.isTrue(s.getMatchParent()));
|
||||||
Assert.assertEquals(asList(
|
Assert.assertEquals(asList(
|
||||||
Student.builder().id(1L).name("dromara").matchParent(true)
|
Student.builder().id(1L).name("dromara").matchParent(true)
|
||||||
.children(asList(Student.builder().id(3L).name("hutool").parentId(1L)
|
.children(asList(Student.builder().id(3L).name("hutool").parentId(1L)
|
||||||
@ -540,7 +541,7 @@ public class EasyStreamTest {
|
|||||||
private Long id;
|
private Long id;
|
||||||
private Long parentId;
|
private Long parentId;
|
||||||
private List<Student> children;
|
private List<Student> children;
|
||||||
private Boolean matchParent = false;
|
private Boolean matchParent;
|
||||||
|
|
||||||
@Tolerate
|
@Tolerate
|
||||||
public Student() {
|
public Student() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user