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

Java实现:筛选高分数据并检测2分钟内高频记录

街机游戏记录处理解决方案

需求回顾

  • 仅筛选分数大于20的记录
  • 将筛选后的记录按时间升序排序
  • 识别满足以下条件的街机ID:
    1. 分数>20的记录总数超过5条
    2. 其中恰好有5条记录落在2分钟时间窗口内
  • 输出符合条件的ID及该窗口内的最早时间

现有代码问题

你当前的代码存在几个关键问题:

  1. 未按街机ID分组,无法单独统计每个ID的记录
  2. 使用Date[]数组处理数据不够灵活,且初始化、添加元素的方式有误
  3. 排序时机不对,应该在所有符合条件的记录收集完成后再排序
  4. 缺少核心的时间窗口判断逻辑

完整实现方案

1. 定义数据实体类

首先创建一个实体类封装单条记录,便于后续处理:

import java.time.LocalDateTime;

public class ArcadeRecord {
    private String arcadeId;
    private LocalDateTime timestamp;
    private int score;

    public ArcadeRecord(String arcadeId, LocalDateTime timestamp, int score) {
        this.arcadeId = arcadeId;
        this.timestamp = timestamp;
        this.score = score;
    }

    // Getter方法
    public String getArcadeId() { return arcadeId; }
    public LocalDateTime getTimestamp() { return timestamp; }
    public int getScore() { return score; }
}

2. 核心处理逻辑

使用Java 8+的Stream API结合滑动窗口思想实现需求:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

public class ArcadeDataProcessor {
    // 时间格式化器,匹配输入的时间格式
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss.SSS");
    // 2分钟对应的秒数,用于时间差判断
    private static final long TWO_MINUTE_THRESHOLD = 120;

    public static void main(String[] args) {
        // 示例原始数据
        String[] rawRecords = {
                "501,20220104 13:12:07.005,25",
                "501,20220104 13:12:07.002,25",
                "500,20220106 09:04:10.013,10",
                "501,20220104 13:12:07.001,25",
                "501,20220104 13:12:07.003,25",
                "501,20220104 13:12:07.004,25",
                "501,20220104 15:20:50.011,25"
        };

        // 步骤1:解析原始数据,筛选分数>20的记录
        List<ArcadeRecord> validRecords = Arrays.stream(rawRecords)
                .map(line -> {
                    String[] parts = line.split(",");
                    String id = parts[0];
                    LocalDateTime time = LocalDateTime.parse(parts[1], DATE_FORMATTER);
                    int score = Integer.parseInt(parts[2]);
                    return new ArcadeRecord(id, time, score);
                })
                .filter(record -> record.getScore() > 20)
                .collect(Collectors.toList());

        // 步骤2:按街机ID分组,每组内按时间升序排序
        Map<String, List<ArcadeRecord>> groupedById = validRecords.stream()
                .collect(Collectors.groupingBy(ArcadeRecord::getArcadeId,
                        Collectors.collectingAndThen(Collectors.toList(), list -> {
                            list.sort(Comparator.comparing(ArcadeRecord::getTimestamp));
                            return list;
                        })));

        // 步骤3:检查每组是否符合条件
        for (Map.Entry<String, List<ArcadeRecord>> entry : groupedById.entrySet()) {
            String arcadeId = entry.getKey();
            List<ArcadeRecord> records = entry.getValue();

            // 先判断总记录数是否超过5条
            if (records.size() <= 5) {
                continue;
            }

            // 滑动窗口检查是否存在恰好5条记录在2分钟内
            for (int i = 0; i <= records.size() - 5; i++) {
                ArcadeRecord windowStart = records.get(i);
                ArcadeRecord windowEnd = records.get(i + 4);
                long timeDiffSeconds = java.time.Duration.between(windowStart.getTimestamp(), windowEnd.getTimestamp()).getSeconds();

                // 先判断当前窗口的5条记录是否在2分钟内
                if (timeDiffSeconds <= TWO_MINUTE_THRESHOLD) {
                    // 检查窗口外是否有其他记录也落在该窗口内,确保恰好5条
                    boolean hasExtraInWindow = false;

                    // 检查窗口前一条记录(如果存在)是否在窗口内
                    if (i > 0) {
                        long prevDiff = java.time.Duration.between(windowStart.getTimestamp(), records.get(i-1).getTimestamp()).getSeconds();
                        if (prevDiff >= -TWO_MINUTE_THRESHOLD) {
                            hasExtraInWindow = true;
                        }
                    }

                    // 检查窗口后一条记录(如果存在)是否在窗口内
                    if (i + 5 < records.size()) {
                        long nextDiff = java.time.Duration.between(windowStart.getTimestamp(), records.get(i+5).getTimestamp()).getSeconds();
                        if (nextDiff <= TWO_MINUTE_THRESHOLD) {
                            hasExtraInWindow = true;
                        }
                    }

                    // 如果没有额外记录在窗口内,说明恰好5条符合条件
                    if (!hasExtraInWindow) {
                        System.out.println("符合条件的街机ID:" + arcadeId);
                        System.out.println("该时间范围最早时间:" + windowStart.getTimestamp().format(DATE_FORMATTER));
                        break; // 找到符合条件的窗口后跳出循环
                    }
                }
            }
        }
    }
}

关键逻辑说明

  • 使用LocalDateTime替代旧的Date类,避免时区问题,时间操作更直观
  • 按ID分组后再排序,确保每个ID的记录都是时间升序的,便于滑动窗口处理
  • 滑动窗口思路:遍历所有可能的连续5条记录,计算首尾时间差是否≤2分钟
  • 额外检查窗口前后的记录,确保该窗口内恰好只有这5条记录,满足需求中的"恰好5条"条件
  • 输出结果直接打印符合条件的ID和窗口最早时间

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 07:45:29