抽取所有CollStream中group相关函数,提取一个groupThen,采纳上一个PR回复的建议,使得代码更加灵活

This commit is contained in:
VampireAchao 2021-12-15 22:18:29 +08:00
parent 7e508a8d4e
commit 6c8ce4ea85
2 changed files with 119 additions and 54 deletions

View File

@ -5,16 +5,10 @@ import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.stream.StreamUtil;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
/**
@ -55,7 +49,7 @@ public class CollStreamUtil {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
return toMap(collection, (v)-> Opt.ofNullable(v).map(key).get(), Function.identity(), isParallel);
return toMap(collection, (v) -> Opt.ofNullable(v).map(key).get(), Function.identity(), isParallel);
}
/**
@ -94,48 +88,48 @@ public class CollStreamUtil {
/**
* 将collection按照规则(比如有相同的班级id)成map<br>
* 将collection按照规则(比如有相同的班级id)成map<br>
* <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
*
* @param collection 需要分的集合
* @param key 的规则
* @param collection 需要分的集合
* @param key 的规则
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @return 后的map
* @return 后的map
*/
public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) {
return groupByKey(collection, key, false);
}
/**
* 将collection按照规则(比如有相同的班级id)成map<br>
* 将collection按照规则(比如有相同的班级id)成map<br>
* <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
*
* @param collection 需要分的集合
* @param key 的规则
* @param collection 需要分的集合
* @param key 的规则
* @param isParallel 是否并行流
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @return 后的map
* @return 后的map
*/
public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key, boolean isParallel) {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
return StreamUtil.of(collection, isParallel).collect(Collectors.groupingBy(key, Collectors.toList()));
return groupThen(collection, key, Collectors.toList(), isParallel);
}
/**
* 将collection按照两个规则(比如有相同的年级id,班级id)成双层map<br>
* 将collection按照两个规则(比如有相同的年级id,班级id)成双层map<br>
* <B>{@code Collection<E> ---> Map<T,Map<U,List<E>>> } </B>
*
* @param collection 需要分的集合
* @param key1 第一个分的规则
* @param key2 第二个分的规则
* @param collection 需要分的集合
* @param key1 第一个分的规则
* @param key2 第二个分的规则
* @param <E> 集合元素类型
* @param <K> 第一个map中的key类型
* @param <U> 第二个map中的key类型
* @return 后的map
* @return 后的map
*/
public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1, Function<E, U> key2) {
return groupBy2Key(collection, key1, key2, false);
@ -143,76 +137,74 @@ public class CollStreamUtil {
/**
* 将collection按照两个规则(比如有相同的年级id,班级id)成双层map<br>
* 将collection按照两个规则(比如有相同的年级id,班级id)成双层map<br>
* <B>{@code Collection<E> ---> Map<T,Map<U,List<E>>> } </B>
*
* @param collection 需要分的集合
* @param key1 第一个分的规则
* @param key2 第二个分的规则
* @param collection 需要分的集合
* @param key1 第一个分的规则
* @param key2 第二个分的规则
* @param isParallel 是否并行流
* @param <E> 集合元素类型
* @param <K> 第一个map中的key类型
* @param <U> 第二个map中的key类型
* @return 后的map
* @return 后的map
*/
public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1,
Function<E, U> key2, boolean isParallel) {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
return StreamUtil.of(collection, isParallel)
.collect(Collectors.groupingBy(key1, Collectors.groupingBy(key2, Collectors.toList())));
return groupThen(collection, key1, Collectors.groupingBy(key2, Collectors.toList()), isParallel);
}
/**
* 将collection按照两个规则(比如有相同的年级id,班级id)成双层map<br>
* 将collection按照两个规则(比如有相同的年级id,班级id)成双层map<br>
* <B>{@code Collection<E> ---> Map<T,Map<U,E>> } </B>
*
* @param collection 需要分的集合
* @param key1 第一个分的规则
* @param key2 第二个分的规则
* @param collection 需要分的集合
* @param key1 第一个分的规则
* @param key2 第二个分的规则
* @param <T> 第一个map中的key类型
* @param <U> 第二个map中的key类型
* @param <E> collection中的泛型
* @return 后的map
* @return 后的map
*/
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) {
return group2Map(collection, key1, key2, false);
}
/**
* 将collection按照两个规则(比如有相同的年级id,班级id)成双层map<br>
* 将collection按照两个规则(比如有相同的年级id,班级id)成双层map<br>
* <B>{@code Collection<E> ---> Map<T,Map<U,E>> } </B>
*
* @param collection 需要分的集合
* @param key1 第一个分的规则
* @param key2 第二个分的规则
* @param collection 需要分的集合
* @param key1 第一个分的规则
* @param key2 第二个分的规则
* @param isParallel 是否并行流
* @param <T> 第一个map中的key类型
* @param <U> 第二个map中的key类型
* @param <E> collection中的泛型
* @return 后的map
* @return 后的map
*/
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection,
Function<E, T> key1, Function<E, U> key2, boolean isParallel) {
if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
return Collections.emptyMap();
}
return StreamUtil.of(collection, isParallel)
.collect(Collectors.groupingBy(key1, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
return groupThen(collection, key1, Collectors.toMap(key2, Function.identity(), (l, r) -> l), isParallel);
}
/**
* 将collection按照规则(比如有相同的班级id)成mapmap中的key为班级idvalue为班级名<br>
* 将collection按照规则(比如有相同的班级id)成mapmap中的key为班级idvalue为班级名<br>
* <B>{@code Collection<E> -------> Map<K,List<V>> } </B>
*
* @param collection 需要分的集合
* @param key 的规则
* @param value 的规则
* @param collection 需要分的集合
* @param key 的规则
* @param value 的规则
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @param <V> List中的value类型
* @return 后的map
* @return 后的map
*/
public static <E, K, V> Map<K, List<V>> groupKeyValue(Collection<E> collection, Function<E, K> key,
Function<E, V> value) {
@ -220,25 +212,61 @@ public class CollStreamUtil {
}
/**
* 将collection按照规则(比如有相同的班级id)成mapmap中的key为班级idvalue为班级名<br>
* 将collection按照规则(比如有相同的班级id)成mapmap中的key为班级idvalue为班级名<br>
* <B>{@code Collection<E> -------> Map<K,List<V>> } </B>
*
* @param collection 需要分的集合
* @param key 的规则
* @param value 的规则
* @param collection 需要分的集合
* @param key 的规则
* @param value 的规则
* @param isParallel 是否并行流
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @param <V> List中的value类型
* @return 后的map
* @return 后的map
*/
public static <E, K, V> Map<K, List<V>> groupKeyValue(Collection<E> collection, Function<E, K> key,
Function<E, V> value, boolean isParallel) {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
return StreamUtil.of(collection, isParallel)
.collect(Collectors.groupingBy(key, Collectors.mapping(value, Collectors.toList())));
return groupThen(collection, key, Collectors.mapping(value, Collectors.toList()), isParallel);
}
/**
* 作为所有groupingBy的公共方法更接近于原生灵活性更强
*
* @param collection 需要分组的集合
* @param key 第一次分组时需要的key
* @param downstream 分组后需要进行的操作
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @param <D> 后续操作的返回值
* @return 分组后的map
*/
public static <E, K, D> Map<K, D> groupThen(Collection<E> collection, Function<E, K> key, Collector<E, ?, D> downstream) {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
return groupThen(collection, key, downstream, false);
}
/**
* 作为所有groupingBy的公共方法更接近于原生灵活性更强
*
* @param collection 需要分组的集合
* @param key 第一次分组时需要的key
* @param downstream 分组后需要进行的操作
* @param isParallel 是否并行流
* @param <E> collection中的泛型
* @param <K> map中的key类型
* @param <D> 后续操作的返回值
* @return 分组后的map
*/
public static <E, K, D> Map<K, D> groupThen(Collection<E> collection, Function<E, K> key, Collector<E, ?, D> downstream, boolean isParallel) {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
return StreamUtil.of(collection, isParallel).collect(Collectors.groupingBy(key, downstream));
}
/**

View File

@ -1,5 +1,6 @@
package cn.hutool.core.collection;
import cn.hutool.core.map.MapUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
@ -7,6 +8,9 @@ import org.junit.Assert;
import org.junit.Test;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
/**
* CollectionStream测试方法
@ -168,6 +172,39 @@ public class CollStreamUtilTest {
Assert.assertEquals(compare, map);
}
@Test
public void testGroupThen() {
// groupThen作为之前所有group函数的公共部分抽取出来并更接近于jdk原生灵活性更强
// 参数null测试
Map<Long, List<Student>> map = CollStreamUtil.groupThen(null, Student::getTermId, Collectors.toList());
Assert.assertEquals(map, Collections.EMPTY_MAP);
// 参数空数组测试
List<Student> list = new ArrayList<>();
map = CollStreamUtil.groupThen(list, Student::getTermId, Collectors.toList());
Assert.assertEquals(map, Collections.EMPTY_MAP);
// 放入元素
list.add(new Student(1, 1, 1, "张三"));
list.add(new Student(1, 2, 1, "李四"));
list.add(new Student(2, 2, 1, "王五"));
// 先根据termId分组再通过classId比较找出最大值所属的那个Student,返回的Optional
Map<Long, Optional<Student>> longOptionalMap = CollStreamUtil.groupThen(list, Student::getTermId, Collectors.maxBy(Comparator.comparing(Student::getClassId)));
Assert.assertEquals("李四", longOptionalMap.get(1L).get().getName());
// 先根据termId分组再转换为Map<studentId,name>
Map<Long, HashMap<Long, String>> groupThen = CollStreamUtil.groupThen(list, Student::getTermId, Collector.of(HashMap::new, (m, v) -> m.put(v.getStudentId(), v.getName()), (l, r) -> l));
Assert.assertEquals(
MapUtil.builder()
.put(1L, MapUtil.builder().put(1L, "李四").build())
.put(2L, MapUtil.builder().put(1L, "王五").build())
.build(),
groupThen);
// 总之如果你是想要group分组后还要进行别的操作用它就对了
}
@Test
public void testTranslate2List() {