如何通过Java Stream按title和author分组并更新Book列表的count字段
按标题和作者分组统计Book列表并更新count字段
问题背景
我需要对一个Book列表进行分组,统计重复条目并更新每个Book对象的count字段。
Book类定义
public class Book{ String title; String author; int count; // 假设已实现Builder模式(如Lombok @Builder或手动实现) public static BookBuilder builder() { return new BookBuilder(); } public static class BookBuilder { private String title; private String author; public BookBuilder title(String title) { this.title = title; return this; } public BookBuilder author(String author) { this.author = author; return this; } public Book build() { Book book = new Book(); book.title = title; book.author = author; book.count = 0; return book; } } // 省略getter/setter方法 public String getTitle() { return title; } public String getAuthor() { return author; } public void setCount(int count) { this.count = count; } }
待处理的Book列表
List<Book> posts = Arrays.asList( Book.builder().title("Book_1").author("ABC").build(), Book.builder().title("Book_2").author("PQR").build(), Book.builder().title("Book_1").author("ABC").build(), Book.builder().title("Book_3").author("XYZ").build() );
需求目标
按title和author字段分组,将每组的统计数量赋值给对应Book对象的count字段。例如title为"Book_1"且author为"ABC"的Book对象count应设为2,其余条目count设为1。
目前已通过Apache Commons的Pair.of()实现分组统计得到Map,但需要将结果转换为List<Book>,每个唯一(title+author)对应一个Book对象,count为分组统计数。
解决方案
方案1:基于已有统计Map转换为目标List
先获取统计结果Map,再遍历转换为List<Book>:
import org.apache.commons.lang3.tuple.Pair; import java.util.List; import java.util.Map; import java.util.stream.Collectors; // 第一步:获取分组统计Map Map<Pair<String, String>, Long> countMap = posts.stream() .collect(Collectors.groupingBy( book -> Pair.of(book.getTitle(), book.getAuthor()), Collectors.counting() )); // 第二步:将Map转换为目标List<Book> List<Book> resultBooks = countMap.entrySet().stream() .map(entry -> { Pair<String, String> key = entry.getKey(); Book book = Book.builder() .title(key.getLeft()) .author(key.getRight()) .build(); book.setCount((int) entry.getValue()); return book; }) .collect(Collectors.toList());
方案2:一步完成分组统计与转换
直接在流式操作中完成所有步骤,无需单独保存Map变量:
import org.apache.commons.lang3.tuple.Pair; import java.util.List; import java.util.stream.Collectors; List<Book> resultBooks = posts.stream() .collect(Collectors.groupingBy( book -> Pair.of(book.getTitle(), book.getAuthor()), Collectors.counting() )) .entrySet().stream() .map(entry -> { Pair<String, String> bookKey = entry.getKey(); Book book = Book.builder() .title(bookKey.getLeft()) .author(bookKey.getRight()) .build(); book.setCount((int) entry.getValue()); return book; }) .collect(Collectors.toList());
方案3:复用原列表中的Book对象(修改原对象)
如果需要保留原列表中的Book对象引用,而非创建新对象,可以采用此方式:
import org.apache.commons.lang3.tuple.Pair; import java.util.List; import java.util.Map; import java.util.stream.Collectors; // 先按分组保存原Book对象列表 Map<Pair<String, String>, List<Book>> groupMap = posts.stream() .collect(Collectors.groupingBy(book -> Pair.of(book.getTitle(), book.getAuthor()))); // 更新每组第一个Book对象的count并收集为结果 List<Book> resultBooks = groupMap.entrySet().stream() .map(entry -> { List<Book> groupBooks = entry.getValue(); Book targetBook = groupBooks.get(0); targetBook.setCount(groupBooks.size()); return targetBook; }) .collect(Collectors.toList());
内容的提问来源于stack exchange,提问作者Akshay Sumbe
相关产品推荐
相关产品推荐

