Java对象属性按时间累加求和逻辑问题排查
问题描述
我有一个Stats对象的列表:
List<Stats> myStats = [ {id:3, numberOfTags:60, latestDateTime:2022-12-08T15:00:00}, {id:1, numberOfTags:50, latestDateTime:2022-12-08T14:00:00}, {id:1, numberOfTags:10, latestDateTime:2022-12-08T10:00:00}, {id:1, numberOfTags:15, latestDateTime:2022-12-08T16:00:00}, {id:2, numberOfTags:20, latestDateTime:2022-12-08T11:00:00}, {id:3, numberOfTags:30, latestDateTime:2022-12-08T12:00:00}, {id:2, numberOfTags:200,latestDateTime:2022-12-09T13:00:00}, {id:2, numberOfTags:40, latestDateTime:2022-12-08T13:00:00} ]
需求是对每个latestDateTime对应的numberOfTags求和,规则为:若某个时间点仅单个id有numberOfTags值,其他id需使用该id最近一次的numberOfTags值补充后再求和。例如2022-12-08T11:00:00时,仅id:2有20个numberOfTags,需补充id:1上一个时间点的10个,总和为30。
预期的目标结果:
{ 2022-12-08T10:00:00 = 10, 2022-12-08T11:00:00 = 30, 2022-12-08T12:00:00 = 60, 2022-12-08T13:00:00 = 80, 2022-12-08T14:00:00 = 120, 2022-12-08T15:00:00 = 150, 2022-12-08T16:00:00 = 115, 2022-12-09T13:00:00 = 275 }
我编写了对应的Java代码,但输出结果不符合预期,请问代码哪里出错了?
附上我的Java代码:
import java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.Comparator; public class Main { public static void main(String[] args) { List<Stats> myStats = List.of( new Stats(1, 10, LocalDateTime.parse("2022-12-08T10:00:00")), new Stats(2, 20, LocalDateTime.parse("2022-12-08T11:00:00")), new Stats(3, 30, LocalDateTime.parse("2022-12-08T12:00:00")), new Stats(2, 40, LocalDateTime.parse("2022-12-08T13:00:00")), new Stats(1, 50, LocalDateTime.parse("2022-12-08T14:00:00")), new Stats(3, 60, LocalDateTime.parse("2022-12-08T15:00:00")), new Stats(1, 15, LocalDateTime.parse("2022-12-08T16:00:00")), new Stats(2, 200, LocalDateTime.parse("2022-12-09T13:00:00")) ); List<Stats> sortedStats = myStats.stream() .sorted(Comparator.comparing(Stats::getLatestDateTime)) .collect(Collectors.toList()); Map<LocalDateTime, Integer> tagCountByDateTime = new HashMap<>(); int previousTagCount = 0; for (Stats stats : sortedStats) { LocalDateTime dateTime =stats.getLatestDateTime(); int tagCount = stats.getNumberOfTags(); if (tagCountByDateTime.containsKey(dateTime)) { tagCountByDateTime.put(dateTime, tagCountByDateTime.get(dateTime) + tagCount); } else { tagCountByDateTime.put(dateTime, previousTagCount + tagCount); } previousTagCount += tagCount; } // Then you can iterate over the map to get the sum of tag counts by date time for (Map.Entry<LocalDateTime, Integer> entry : tagCountByDateTime.entrySet()) { LocalDateTime dateTime = entry.getKey(); int tagCount = entry.getValue(); System.out.println(dateTime + ": " + tagCount); } } } class Stats { private int id; private int numberOfTags; private LocalDateTime latestDateTime; public Stats(int id, int numberOfTags, LocalDateTime latestDateTime) { this.id = id; this.numberOfTags = numberOfTags; this.latestDateTime = latestDateTime; } public int getId() { return id; } public int getNumberOfTags() { return numberOfTags; } public LocalDateTime getLatestDateTime() { return latestDateTime; } }
问题分析与修正
你的代码核心错误在于没有按id跟踪每个id的最新标签数,而是用一个全局的previousTagCount累加所有标签数,这完全不符合需求中“每个id单独取最近值”的规则。
具体问题点:
previousTagCount是全局累加变量,会把所有历史标签数无差别加总,而非每个id保留最新值- 处理同一时间点的多个id时,仅简单累加当前id的标签数,未补充其他id的最新值
- 无法维护每个id的状态变化,导致后续时间点的求和逻辑完全偏离需求
修正思路
- 用
Map<Integer, Integer>跟踪每个id的最新标签数,key为id,value为该id当前的最新标签数 - 先收集所有唯一时间点并排序,确保按时间顺序处理
- 对每个时间点:
- 先更新该时间点所有id的最新标签数
- 再计算所有id的最新标签数之和,作为该时间点的结果
修正后的代码
import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Stats> myStats = List.of( new Stats(1, 10, LocalDateTime.parse("2022-12-08T10:00:00")), new Stats(2, 20, LocalDateTime.parse("2022-12-08T11:00:00")), new Stats(3, 30, LocalDateTime.parse("2022-12-08T12:00:00")), new Stats(2, 40, LocalDateTime.parse("2022-12-08T13:00:00")), new Stats(1, 50, LocalDateTime.parse("2022-12-08T14:00:00")), new Stats(3, 60, LocalDateTime.parse("2022-12-08T15:00:00")), new Stats(1, 15, LocalDateTime.parse("2022-12-08T16:00:00")), new Stats(2, 200, LocalDateTime.parse("2022-12-09T13:00:00")) ); // 按时间分组,同一时间点的Stats集合在一起 Map<LocalDateTime, List<Stats>> statsByTime = myStats.stream() .collect(Collectors.groupingBy(Stats::getLatestDateTime)); // 获取所有时间点并按自然顺序排序 List<LocalDateTime> sortedTimes = new ArrayList<>(statsByTime.keySet()); sortedTimes.sort(Comparator.naturalOrder()); // 维护每个id的最新标签数 Map<Integer, Integer> latestTagPerId = new HashMap<>(); // 存储最终结果,用LinkedHashMap保证输出顺序与时间顺序一致 Map<LocalDateTime, Integer> result = new LinkedHashMap<>(); for (LocalDateTime time : sortedTimes) { // 更新当前时间点所有id的最新标签数 List<Stats> currentStats = statsByTime.get(time); for (Stats stat : currentStats) { latestTagPerId.put(stat.getId(), stat.getNumberOfTags()); } // 计算所有id的最新标签数之和 int sum = latestTagPerId.values().stream().mapToInt(Integer::intValue).sum(); result.put(time, sum); } // 输出结果 for (Map.Entry<LocalDateTime, Integer> entry : result.entrySet()) { System.out.println(entry.getKey() + " = " + entry.getValue()); } } } class Stats { private int id; private int numberOfTags; private LocalDateTime latestDateTime; public Stats(int id, int numberOfTags, LocalDateTime latestDateTime) { this.id = id; this.numberOfTags = numberOfTags; this.latestDateTime = latestDateTime; } public int getId() { return id; } public int getNumberOfTags() { return numberOfTags; } public LocalDateTime getLatestDateTime() { return latestDateTime; } }
代码说明
statsByTime:将原始数据按时间分组,方便快速获取每个时间点的所有Stats记录sortedTimes:确保按时间顺序处理,保证id的最新值严格遵循时间线更新latestTagPerId:实时维护每个id的最新标签数,每次处理时间点时先更新该时间点的id值,再求和LinkedHashMap:保证结果输出顺序与时间顺序一致,符合直观认知
运行修正后的代码,输出结果将完全符合预期。
内容的提问来源于stack exchange,提问作者Eddie Kwasi Dankie
相关产品推荐
相关产品推荐

