From 70283b1191c93e12d8f44d670eead8b7775a0b27 Mon Sep 17 00:00:00 2001 From: mbarriola <85458535+mbarriola@users.noreply.github.com> Date: Sun, 22 Aug 2021 16:57:09 -0400 Subject: [PATCH] Bael 5066 aggregate over multiple fields (#11156) * Commit source code to branch * BAEL-5065 improvement of groupBy with complex key * Aggregation of multiple attributes of a grouped result --- .../java_16_features/groupingby/BlogPost.java | 7 ++- .../JavaGroupingByCollectorUnitTest.java | 62 ++++++++++++++++--- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPost.java b/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPost.java index adaa1044ff..960a75a58e 100644 --- a/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPost.java +++ b/core-java-modules/core-java-16/src/main/java/com/baeldung/java_16_features/groupingby/BlogPost.java @@ -1,5 +1,8 @@ package com.baeldung.java_16_features.groupingby; +import java.util.IntSummaryStatistics; + + public class BlogPost { private String title; @@ -7,7 +10,9 @@ public class BlogPost { private BlogPostType type; private int likes; record AuthPostTypesLikes(String author, BlogPostType type, int likes) {}; - + record PostcountTitlesLikesStats(long postCount, String titles, IntSummaryStatistics likesStats){}; + record TitlesBoundedSumOfLikes(String titles, int boundedSumOfLikes) {}; + public BlogPost(String title, String author, BlogPostType type, int likes) { this.title = title; this.author = author; diff --git a/core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/groupingby/JavaGroupingByCollectorUnitTest.java b/core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/groupingby/JavaGroupingByCollectorUnitTest.java index 0e926246ff..0dea142658 100644 --- a/core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/groupingby/JavaGroupingByCollectorUnitTest.java +++ b/core-java-modules/core-java-16/src/test/java/com/baeldung/java_16_features/groupingby/JavaGroupingByCollectorUnitTest.java @@ -5,6 +5,8 @@ import static java.util.stream.Collectors.averagingInt; import static java.util.stream.Collectors.counting; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.groupingByConcurrent; +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.mapping; import static java.util.stream.Collectors.maxBy; @@ -13,6 +15,7 @@ import static java.util.stream.Collectors.summingInt; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.offset; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -201,9 +204,9 @@ public class JavaGroupingByCollectorUnitTest { @Test public void givenAListOfPosts_whenGroupedByComplexMapPairKeyType_thenGetAMapBetweenPairAndList() { - + Map, List> postsPerTypeAndAuthor = posts.stream() - .collect(groupingBy(post -> new ImmutablePair<>(post.getType(), post.getAuthor()))); + .collect(groupingBy(post -> new ImmutablePair<>(post.getType(), post.getAuthor()))); List result = postsPerTypeAndAuthor.get(new ImmutablePair<>(BlogPostType.GUIDE, "Author 1")); @@ -218,7 +221,7 @@ public class JavaGroupingByCollectorUnitTest { @Test public void givenAListOfPosts_whenGroupedByComplexMapKeyType_thenGetAMapBetweenTupleAndList() { - + Map> postsPerTypeAndAuthor = posts.stream() .collect(groupingBy(post -> new Tuple(post.getType(), post.getAuthor()))); @@ -232,12 +235,12 @@ public class JavaGroupingByCollectorUnitTest { assertThat(blogPost.getType()).isEqualTo(BlogPostType.GUIDE); assertThat(blogPost.getAuthor()).isEqualTo("Author 1"); } - + @Test public void givenAListOfPosts_whenGroupedByRecord_thenGetAMapBetweenRecordAndList() { - + Map> postsPerTypeAndAuthor = posts.stream() - .collect(groupingBy(post -> new BlogPost.AuthPostTypesLikes(post.getAuthor(), post.getType(), post.getLikes()))); + .collect(groupingBy(post -> new BlogPost.AuthPostTypesLikes(post.getAuthor(), post.getType(), post.getLikes()))); List result = postsPerTypeAndAuthor.get(new BlogPost.AuthPostTypesLikes("Author 1", BlogPostType.GUIDE, 20)); @@ -250,5 +253,50 @@ public class JavaGroupingByCollectorUnitTest { assertThat(blogPost.getAuthor()).isEqualTo("Author 1"); assertThat(blogPost.getLikes()).isEqualTo(20); } - + + @Test + public void givenListOfPosts_whenGroupedByAuthor_thenGetAMapUsingCollectingAndThen() { + + Map postsPerAuthor = posts.stream() + .collect(groupingBy(BlogPost::getAuthor, collectingAndThen(toList(), list -> { + long count = list.stream() + .map(BlogPost::getTitle) + .collect(counting()); + String titles = list.stream() + .map(BlogPost::getTitle) + .collect(joining(" : ")); + IntSummaryStatistics summary = list.stream() + .collect(summarizingInt(BlogPost::getLikes)); + return new BlogPost.PostcountTitlesLikesStats(count, titles, summary); + }))); + + BlogPost.PostcountTitlesLikesStats result = postsPerAuthor.get("Author 1"); + assertThat(result.postCount()).isEqualTo(3L); + assertThat(result.titles()).isEqualTo("News item 1 : Programming guide : Tech review 2"); + assertThat(result.likesStats().getMax()).isEqualTo(20); + assertThat(result.likesStats().getMin()).isEqualTo(15); + assertThat(result.likesStats().getAverage()).isEqualTo(16.666d, offset(0.001d)); + } + + @Test + public void givenListOfPosts_whenGroupedByAuthor_thenGetAMapUsingToMap() { + + int maxValLikes = 17; + Map postsPerAuthor = posts.stream() + .collect(toMap(BlogPost::getAuthor, post -> { + int likes = (post.getLikes() > maxValLikes) ? maxValLikes : post.getLikes(); + return new BlogPost.TitlesBoundedSumOfLikes(post.getTitle(), likes); + }, (u1, u2) -> { + int likes = (u2.boundedSumOfLikes() > maxValLikes) ? maxValLikes : u2.boundedSumOfLikes(); + return new BlogPost.TitlesBoundedSumOfLikes(u1.titles() + .toUpperCase() + " : " + + u2.titles() + .toUpperCase(), + u1.boundedSumOfLikes() + likes); + })); + + BlogPost.TitlesBoundedSumOfLikes result = postsPerAuthor.get("Author 1"); + assertThat(result.titles()).isEqualTo("NEWS ITEM 1 : PROGRAMMING GUIDE : TECH REVIEW 2"); + assertThat(result.boundedSumOfLikes()).isEqualTo(47); + } }