0

0

Java中计算列表数据中按条件分组的连续失败时长

霞舞

霞舞

发布时间:2025-12-12 21:18:01

|

190人浏览过

|

来源于php中文网

原创

Java中计算列表数据中按条件分组的连续失败时长

本教程详细介绍了如何在java中处理包含时间序列和状态信息的列表数据,以计算每个实体(如用户)的累积失败时长。通过将数据按实体分组,并利用java stream api或第三方seq库进行排序和有状态遍历,精确地统计从“失败”状态开始到下一个“成功”状态结束的持续时间。文章提供了具体的代码示例,并讨论了实现细节及注意事项。

在现代数据处理中,我们经常需要从一系列事件记录中提取有意义的聚合信息。一个常见场景是,给定一个包含实体名称、事件日期和状态(例如“成功”或“失败”)的列表,我们需要计算每个实体在特定条件下的累计时长。本教程将以计算“连续失败时长”为例,详细讲解如何使用Java的Stream API以及第三方库Seq来高效解决此类问题。

问题描述

假设我们有一组按时间顺序排列的事件记录,每条记录包含一个实体名称(name)、事件发生的年份(date)和事件状态(status,可以是"success"或"fail")。我们需要为每个实体计算其总的“失败时长”。失败时长定义为:从一个“失败”状态开始,到紧随其后的第一个“成功”状态结束的时间跨度。如果在一个失败周期中出现多个连续的失败事件,它们将被视为同一失败周期的延续。

示例数据:

[
   {"name":"john", "date":2015, "status":"success"},
   {"name":"john", "date":2013, "status":"fail"},
   {"name":"chris", "date":2013, "status":"success"},
   {"name":"john", "date":2012, "status":"fail"},
   {"name":"john", "date":2009, "status":"success"},
   {"name":"chris", "date":2007, "status":"fail"},
   {"name":"john", "date":2005, "status":"fail"},
]

根据上述定义,对于john:

立即学习Java免费学习笔记(深入)”;

MusicLM
MusicLM

谷歌平台的AI作曲工具,用文字生成音乐

下载
  • 2005年失败,下一个成功是2009年,失败时长为 2009 - 2005 = 4 年。
  • 2012年失败,2013年再次失败(视为同一失败周期),下一个成功是2015年,失败时长为 2015 - 2012 = 3 年。
  • john的总失败时长为 4 + 3 = 7 年。

对于chris:

  • 2007年失败,下一个成功是2013年,失败时长为 2013 - 2007 = 6 年。
  • chris的总失败时长为 6 年。

数据模型定义

为了更好地组织和处理数据,我们首先定义一个Java类来表示每条记录,而不是直接使用HashMap。这提供了更好的类型安全性和代码可读性

public class Record {
    public String name;
    public Integer date; // 使用Integer表示年份
    public String status;

    public Record(String name, Integer date, String status) {
        this.name = name;
        this.date = date;
        this.status = status;
    }

    @Override
    public String toString() {
        return "Record{" +
               "name='" + name + '\'' +
               ", date=" + date +
               ", status='" + status + '\'' +
               '}';
    }
}

核心计算逻辑

解决此类问题的关键在于对数据进行分组和按时间排序,并在遍历过程中维护一个状态。具体步骤如下:

  1. 按实体名称分组:首先,将所有记录根据其name字段进行分组。这样,我们可以独立地处理每个实体的事件序列。
  2. 组内按日期排序:对于每个实体组,必须将其内部的记录按照date字段升序排序。这是确保计算逻辑正确性的前提,因为失败时长的计算依赖于事件的先后顺序。
  3. 有状态遍历计算
    • 在遍历每个实体排序后的记录时,我们需要维护一个变量来记录当前是否处于一个失败周期中,以及该失败周期的起始日期。我们可以使用一个Integer类型的变量lastFailDate,初始值为null。
    • 当遇到一条状态为"fail"的记录时:
      • 如果lastFailDate为null,表示这是一个新的失败周期的开始,我们将当前记录的date赋值给lastFailDate。
      • 如果lastFailDate不为null,表示失败周期正在持续,我们不需要更新lastFailDate(因为我们只关心失败的起始点)。
    • 当遇到一条状态为"success"的记录时:
      • 如果lastFailDate不为null,表示当前有一个未结束的失败周期。此时,计算当前成功记录的date与lastFailDate之差,作为本次失败的时长,并将其累加到该实体的总失败时长中。
      • 计算完成后,将lastFailDate重置为null,表示该失败周期已经结束。
    • 如果lastFailDate为null,则忽略当前成功记录,因为它没有前置的失败周期。

使用Java Stream API实现

Java 8引入的Stream API为集合处理提供了强大而灵活的工具。我们可以利用它来实现上述逻辑。

import java.util.List;
import java.util.Map;
import java.util.Comparator;
import java.util.stream.Collectors;

public class FailureDurationCalculator {

    public static Map calculateFailureDurationWithStream(List records) {
        return records.stream()
            // 1. 按名称分组:将所有记录根据其name字段分组,得到Map>
            .collect(Collectors.groupingBy(r -> r.name))
            .entrySet().stream() // 将Map的entrySet转换为Stream,以便进一步处理每个分组
            // 2. 对每个分组计算失败时长,并收集到最终的Map中
            .collect(Collectors.toMap(Map.Entry::getKey, entry -> {
                // 使用数组作为可变变量,以在Lambda表达式中存储上一次失败的日期。
                // Stream操作通常是无状态的,但这里需要维护一个跨记录的状态。
                Integer[] lastFailDate = new Integer[]{null};

                return entry.getValue().stream()
                    // 3. 对每个分组内的记录按日期升序排序
                    .sorted(Comparator.comparing(r -> r.date))
                    .mapToInt(record -> {
                        if ("fail".equals(record.status) && lastFailDate[0] == null) {
                            // 遇到失败,且当前没有正在进行的失败期,记录失败开始日期
                            lastFailDate[0] = record.date;
                        } else if ("success".equals(record.status) && lastFailDate[0] != null) {
                            // 遇到成功,且有正在进行的失败期,计算时长
                            int duration = record.date - lastFailDate[0];
                            lastFailDate[0] = null; // 重置失败开始日期,表示该失败周期已结束
                            return duration;
                        }
                        return 0; // 其他情况(如连续失败、成功后无失败等)不产生时长
                    })
                    .sum(); // 累加所有计算出的失败时长,得到该实体的总失败时长
            }));
    }

    public static void main(String[] args) {
        List records = List.of(
            new Record("john", 2015, "success"),
            new Record("john", 2013, "fail"),
            new Record("chris", 2013, "success"),
            new Record("john", 2012, "fail"),
            new Record("john", 2009, "success"),
            new Record("chris", 2007, "fail"),
            new Record("john", 2005, "fail")
        );

        Map failureDurations = calculateFailureDurationWithStream(records);
        System.out.println("使用Stream API计算的失败时长: " + failureDurations); // 预期输出: {chris=6, john=7}
    }
}

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

236

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

458

2024.03.01

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

1

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

1

2026.01.29

java成品学习网站推荐大全
java成品学习网站推荐大全

本专题整合了java成品网站、在线成品网站源码、源码入口等等相关内容,阅读专题下面的文章了解更多详细推荐内容。

0

2026.01.29

Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

0

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.29

clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

24

2026.01.29

clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址
clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址

clawdbot龙虾机器人官网入口:https://clawd.bot/,clawdbot ai是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

16

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 7.9万人学习

Java 教程
Java 教程

共578课时 | 53.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号