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

如何使用Stream API按地点分组并按日期(忽略时间)统计事件数

问题:使用Stream API按地点分组并统计不同日期数量

需求

将Event对象列表按location分组,同一地点下统计**不同日期(忽略时间部分)**的数量,最终得到Map<String, Integer>类型结果:key为location,value为该地点的不同日期数。

Event类代码

public class Event {
    String location;
    String date;
    String count; 
 
    public String getCount() {
        return count;
    }

    public void setCount(String count) {
        this.count = count;
    }
    public String getLocation() {
        return location;
    }

    public String getDate() {
        return date;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public void setDate(String date) {
        this.date = date;
    }
} 

测试数据

注意:原测试代码存在复用同一Event对象的问题,会导致列表中所有元素属性一致,正确的测试代码应该为每个事件创建新对象:

List<Event> events = new ArrayList<>();

Event event1 = new Event();
event1.setLocation("98.55.62.162");
event1.setDate("09/17/2022 12:05:43 PM");
events.add(event1);

Event event2 = new Event();
event2.setLocation("98.55.62.162");
event2.setDate("09/16/2022 12:05:45 PM");
events.add(event2);

Event event3 = new Event();
event3.setLocation("98.55.62.162");
event3.setDate("09/16/2022 12:05:47 PM");
events.add(event3);

Event event4 = new Event();
event4.setLocation("98.55.62.162");
event4.setDate("09/15/2022 12:05:49 PM");
events.add(event4);

Event event5 = new Event();
event5.setLocation("98.55.62.163");
event5.setDate("09/17/2022 12:05:31 PM");
events.add(event5);

Event event6 = new Event();
event6.setLocation("98.55.62.163");
event6.setDate("09/16/2022 12:05:22 PM");
events.add(event6);

Event event7 = new Event();
event7.setLocation("98.55.62.163");
event7.setDate("09/16/2022 12:05:11 PM");
events.add(event7);

尝试过的代码

Map<String, List<Event>> eventMap = events.stream().collect(Collectors.groupingBy(s -> s.getLocation()));

该代码仅实现了按地点分组,未统计不同日期的数量。

期望输出

{"98.55.62.162":3 , "98.55.62.163":2}

解决方案

1. 使用Stream API实现

核心思路:按地点分组后,提取每个事件的日期部分(忽略时间),用Set去重后统计集合大小。

首先定义一个健壮的日期提取方法(避免字符串截取的兼容性问题):

private static String extractDatePart(String dateStr) {
    // 匹配测试数据的日期格式:MM/dd/yyyy hh:mm:ss a
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss a");
    LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
    // 返回仅包含日期部分的字符串
    return dateTime.toLocalDate().toString();
}

然后通过Stream API完成分组和统计:

Map<String, Integer> locationDateCount = events.stream()
    .collect(Collectors.groupingBy(
        Event::getLocation, // 按location分组
        Collectors.collectingAndThen(
            Collectors.mapping(
                event -> extractDatePart(event.getDate()), // 提取日期部分
                Collectors.toSet() // 存入Set自动去重
            ),
            Set::size // 统计去重后的日期数量
        )
    ));

2. 使用循环实现

如果偏好传统循环方式,也可以通过Map+Set的组合实现:

// 先收集每个地点对应的所有唯一日期
Map<String, Set<String>> locationDateSet = new HashMap<>();
for (Event event : events) {
    String location = event.getLocation();
    String datePart = extractDatePart(event.getDate());
    // 若地点不存在则创建新的Set,否则直接添加日期
    locationDateSet.computeIfAbsent(location, k -> new HashSet<>()).add(datePart);
}

// 转换为最终的统计结果
Map<String, Integer> locationDateCount = new HashMap<>();
for (Map.Entry<String, Set<String>> entry : locationDateSet.entrySet()) {
    locationDateCount.put(entry.getKey(), entry.getValue().size());
}

内容的提问来源于stack exchange,提问作者Jordan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 22:25:25