From 34835939d20aa282258f4b28983b81dfb80db235 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 5 Jul 2022 21:54:41 +0800 Subject: [PATCH] add method --- CHANGELOG.md | 1 + .../cn/hutool/core/stream/CollectorUtil.java | 61 ++++++++++++++----- .../hutool/core/stream/CollectorUtilTest.java | 30 +++++++++ 3 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 6decf0615..a894d1f92 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * 【core 】 合成注解SyntheticAnnotation提取为接口,并为实现类添加注解选择器和属性处理器(pr#678@Gitee) * 【core 】 增加BeanValueProvider(issue#I5FBHV@Gitee) * 【core 】 Convert工具类中,新增中文大写数字金额转换为数字工具方法(pr#674@Gitee) +* 【core 】 新增CollectorUtil.reduceListMap()(pr#676@Gitee) * ### 🐞Bug修复 diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 5d9c9d87a..9bd5a7727 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -3,12 +3,13 @@ package cn.hutool.core.stream; import cn.hutool.core.lang.Opt; import cn.hutool.core.util.StrUtil; +import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; -import java.util.List; import java.util.StringJoiner; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; @@ -99,26 +100,23 @@ public class CollectorUtil { public static > Collector groupingBy(Function classifier, Supplier mapFactory, Collector downstream) { - Supplier downstreamSupplier = downstream.supplier(); - BiConsumer downstreamAccumulator = downstream.accumulator(); - BiConsumer, T> accumulator = (m, t) -> { - K key = Opt.ofNullable(t).map(classifier).orElse(null); - A container = m.computeIfAbsent(key, k -> downstreamSupplier.get()); + final Supplier downstreamSupplier = downstream.supplier(); + final BiConsumer downstreamAccumulator = downstream.accumulator(); + final BiConsumer, T> accumulator = (m, t) -> { + final K key = Opt.ofNullable(t).map(classifier).orElse(null); + final A container = m.computeIfAbsent(key, k -> downstreamSupplier.get()); downstreamAccumulator.accept(container, t); }; - BinaryOperator> merger = mapMerger(downstream.combiner()); - @SuppressWarnings("unchecked") - Supplier> mangledFactory = (Supplier>) mapFactory; + final BinaryOperator> merger = mapMerger(downstream.combiner()); + @SuppressWarnings("unchecked") final Supplier> mangledFactory = (Supplier>) mapFactory; if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { return new SimpleCollector<>(mangledFactory, accumulator, merger, CH_ID); } else { - @SuppressWarnings("unchecked") - Function downstreamFinisher = (Function) downstream.finisher(); - Function, M> finisher = intermediate -> { + @SuppressWarnings("unchecked") final Function downstreamFinisher = (Function) downstream.finisher(); + final Function, M> finisher = intermediate -> { intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v)); - @SuppressWarnings("unchecked") - M castResult = (M) intermediate; + @SuppressWarnings("unchecked") final M castResult = (M) intermediate; return castResult; }; return new SimpleCollector<>(mangledFactory, accumulator, merger, finisher, CH_NOID); @@ -214,5 +212,40 @@ public class CollectorUtil { }; } + /** + * 聚合这种数据类型:{@code Collection> => Map>} + * 其中key相同的value,会累加到List中 + * + * @param key的类型 + * @param value的类型 + * @return 聚合后的map + * @since 5.8.5 + */ + public static Collector, ?, Map>> reduceListMap() { + return reduceListMap(HashMap::new); + } + + /** + * 聚合这种数据类型:{@code Collection> => Map>} + * 其中key相同的value,会累加到List中 + * + * @param mapSupplier 可自定义map的类型如concurrentHashMap等 + * @param key的类型 + * @param value的类型 + * @param 返回值的类型 + * @return 聚合后的map + * @since 5.8.5 + */ + public static >> Collector, ?, R> reduceListMap(final Supplier mapSupplier) { + return Collectors.reducing(mapSupplier.get(), value -> { + final R result = mapSupplier.get(); + value.forEach((k, v) -> result.computeIfAbsent(k, i -> new ArrayList<>()).add(v)); + return result; + }, (l, r) -> { + r.forEach((k, v) -> l.computeIfAbsent(k, i -> new ArrayList<>()).addAll(v)); + return l; + } + ); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java new file mode 100644 index 000000000..0c8e3c560 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/stream/CollectorUtilTest.java @@ -0,0 +1,30 @@ +package cn.hutool.core.stream; + +import cn.hutool.core.map.MapUtil; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class CollectorUtilTest { + @Test + public void reduceListMapTest() { + final Set> nameScoreMapList = StreamUtil.of( + // 集合内的第一个map,包含两个key value + MapUtil.builder("苏格拉底", 1).put("特拉叙马霍斯", 3).build(), + MapUtil.of("苏格拉底", 2), + MapUtil.of("特拉叙马霍斯", 1), + MapUtil.of("特拉叙马霍斯", 2) + ).collect(Collectors.toSet()); + // 执行聚合 + final Map> nameScoresMap = nameScoreMapList.stream().collect(CollectorUtil.reduceListMap()); + + Assert.assertEquals(MapUtil.builder("苏格拉底", Arrays.asList(1, 2)) + .put("特拉叙马霍斯", Arrays.asList(3, 1, 2)).build(), + nameScoresMap); + } +}