Java中实现分组、排序并选取含合并字段值的单条记录
解决思路与代码实现
你需要实现的是按CustId分组后,同时完成两个操作:选出每组内Time倒序的第一条记录(最新事件),并将该组所有Product字段值用#拼接后更新到这条记录的Product字段。可以通过一次分组遍历完成逻辑合并,避免两次流处理提升效率。
合并后的代码实现
// 一次分组完成排序取最新、拼接Product并更新字段的逻辑 Map<String, CustEvent> resultMap = custEventList.stream() .collect(Collectors.groupingBy( CustEvent::getCustId, Collectors.collectingAndThen( Collectors.toList(), groupList -> { // 1. 对组内事件按Time倒序排序,获取最新记录 CustEvent latestEvent = groupList.stream() .sorted(Comparator.comparing(CustEvent::getTime, Comparator.nullsFirst(Comparator.naturalOrder())).reversed()) .findFirst() .orElse(null); // 2. 拼接该组所有Product字段值 String combinedProducts = groupList.stream() .map(CustEvent::getProduct) .collect(Collectors.joining("#")); // 3. 更新最新记录的Product字段 if (latestEvent != null) { latestEvent.setProduct(combinedProducts); } return latestEvent; } ) )); // 若需要结果列表,直接提取Map的value集合即可 List<CustEvent> resultList = new ArrayList<>(resultMap.values());
代码说明
- 一次分组避免重复遍历:在
collectingAndThen的转换逻辑中,直接对分组后的列表同时处理排序取最新、拼接Product两个操作,无需两次遍历原列表。 - 空安全处理:用
findFirst().orElse(null)替代原代码的get(0),避免空列表抛出索引越界异常。 - 字段更新:直接修改选出的最新事件的
Product字段,最终Map的value即为处理完成的目标记录。
不可变对象替代方案
如果CustEvent是不可变对象(无setProduct方法),可以通过构造新对象完成逻辑:
Map<String, CustEvent> resultMap = custEventList.stream() .collect(Collectors.groupingBy( CustEvent::getCustId, Collectors.collectingAndThen( Collectors.toList(), groupList -> { CustEvent latest = groupList.stream() .sorted(Comparator.comparing(CustEvent::getTime, Comparator.nullsFirst(Comparator.naturalOrder())).reversed()) .findFirst() .orElse(null); String products = groupList.stream().map(CustEvent::getProduct).collect(Collectors.joining("#")); // 假设CustEvent提供含参构造函数 return new CustEvent(latest.getCustId(), latest.getTime(), products); } ) ));
内容的提问来源于stack exchange,提问作者αƞjiβ
相关产品推荐
相关产品推荐

