Java如何按小时区间对列表内同描述元素实现去重
实现方案
核心逻辑是给每个元素生成唯一的去重标识,标识由两部分拼接组成:
- 元素的
description字段值 - 时间戳按业务时区截断到小时粒度后的时间值
同一个小时内、description相同的元素生成的标识完全一致,通过Map过滤掉重复标识对应的后续元素即可,整体时间复杂度O(n),500条数据的量级没有任何性能压力。
注意处理google.protobuf.Timestamp时必须显式指定业务对应的时区,不要依赖服务器默认时区,避免跨环境部署时出现小时计算偏差。
具体代码实现
首先确保你的MyObject类添加了两个私有字段的getter方法,否则无法读取属性值。
import com.google.protobuf.Timestamp; import java.time.*; import java.util.*; public class MyObjectDeduplicator { // 替换为你业务实际使用的时区 private static final ZoneId BIZ_ZONE = ZoneId.of("Asia/Shanghai"); public static List<MyObject> removeDuplicateInSameHour(List<MyObject> sourceList) { // 用LinkedHashMap保留元素在原列表中首次出现的顺序 Map<String, MyObject> dedupMap = new LinkedHashMap<>(); for (MyObject item : sourceList) { // 1. 将protobuf Timestamp转为带时区的时间,截断到小时粒度 Timestamp protoTs = item.getTimestamp(); Instant instant = Instant.ofEpochSecond(protoTs.getSeconds(), protoTs.getNanos()); long hourEpochMilli = instant.atZone(BIZ_ZONE) .truncatedTo(ChronoUnit.HOURS) .toInstant() .toEpochMilli(); // 2. 生成去重key String dedupKey = item.getDescription() + "_" + hourEpochMilli; // 3. key不存在时才放入,即保留同组第一个出现的元素 dedupMap.putIfAbsent(dedupKey, item); // 如果需要保留同组最后一个出现的元素,把上面的putIfAbsent换成put(dedupKey, item)即可 } return new ArrayList<>(dedupMap.values()); } }
调用时直接传入原列表即可得到去重后的结果:
List<MyObject> resultList = MyObjectDeduplicator.removeDuplicateInSameHour(myList);
规则匹配验证
针对你给出的两个测试场景,逻辑完全符合预期:
- 对于
06-07-2022T01:30:00, "some random description"和06-07-2022T01:35:00, "some random description":两个时间截断到小时为同一值,description相同,判定为重复,仅保留1个元素 - 对于
06-07-2022T01:30:00, "some random description"和06-07-2022T03:20:00, "some random description":两个时间截断到小时分别为1点和3点,去重key不同,两个元素均会保留
内容的提问来源于stack exchange,提问作者TheStranger
相关产品推荐
相关产品推荐

