You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:33:14