Java8 stream分组按某字段取最大值

摘要:
场景项目中有这样的场景:一个商品可以参与多个类型的促销活动,如满减、满赠、买赠、优惠券等活动;相同类型的活动也可能有多个;每个活动根据类型和具体的业务字段有一个活动标签,如满减活动,消费满200元减20元,活动标签为满200减20商品列表的界面上需要展示每个商品的促销活动标签,相同类型活动有多个只展示最新一个创建的活动标签假定活动id是递增的,新创建的活动id值更大促销活动类型定义:@Getter

场景

项目中有这样的场景:

  • 一个商品可以参与多个类型的促销活动,如满减、满赠、买赠、优惠券等活动;
  • 相同类型的活动也可能有多个;
  • 每个活动根据类型和具体的业务字段有一个活动标签,如满减活动,消费满200元减20元,活动标签为满200减20
  • 商品列表的界面上需要展示每个商品的促销活动标签,相同类型活动有多个只展示最新一个创建的活动标签
  • 假定活动id是递增的,新创建的活动id值更大

促销活动类型定义:

@Getter
@AllArgsConstructor
private static enum PromotionType {
    FULL_MINUS("FULL_MINUS", "满减"),
    FULL_GIFT("FULL_GIFT","满赠"),
    BUY_GIFT("BUY_GIFT","买赠"),
    COUPON("COUPON","优惠券");

    private String name;
    private String description;
}

促销活动模型vo定义:

@NoArgsConstructor
@AllArgsConstructor
@Data
private static class PromotionActivityVo implements Serializable {

    // 活动id
    private Integer id;

    // 活动类型
    private PromotionType type;

    // 活动标签
    private String label;
}

测试用例:

// 假定某商品参与了如下5个促销活动
PromotionActivityVo activity1 = new PromotionActivityVo(1, PromotionType.FULL_MINUS, "满200减20");
PromotionActivityVo activity2 = new PromotionActivityVo(2, PromotionType.FULL_MINUS, "满300减30");
PromotionActivityVo activity3 = new PromotionActivityVo(3, PromotionType.BUY_GIFT, "买180赠10");
PromotionActivityVo activity4 = new PromotionActivityVo(4, PromotionType.FULL_GIFT, "满150赠5");
PromotionActivityVo activity5 = new PromotionActivityVo(5, PromotionType.FULL_GIFT, "满300赠25");
List<PromotionActivityVo> activities = Lists.newArrayList(activity1, activity2, activity3, activity4, activity5);

预期输出结果为:
满300减30, 满300赠25, 买180赠10

注:

  • 按促销活动类型里定义的顺序输出
  • 输出第2个满减活动和第5个满赠活动因为同类型的活动它们的id值更大
  • 优惠券活动没有参与,因此没有该活动的促销标签

思路

  1. 将促销活动列表按促销活动类型分组生成一个map,其中key为促销活动类型,value为活动模型vo
  2. 将促销活动类型转为stream然后根据map取值,过滤掉空值,转换为label的列表

实现

Map<PromotionType, PromotionActivityVo> promotionTypeMap = activities.stream().collect(Collectors.groupingBy(PromotionActivityVo::getType
                , Collectors.collectingAndThen(Collectors.reducing((o1, o2) ->
                        Long.valueOf(o1.getId()).compareTo(Long.valueOf(o2.getId())) > 0 ? o1 : o2), Optional::get)));
List<String> labels = Arrays.stream(PromotionType.values()).map(promotionTypeMap::get).filter(Objects::nonNull).map(PromotionActivityVo::getLabel).collect(Collectors.toList());
System.out.println(labels);

其中第1步转换map可用另一种方式:

Map<PromotionType, PromotionActivityVo> promotionTypeMap = activities.stream().collect(Collectors.toMap(PromotionActivityVo::getType, Function.identity(), (o1, o2) -> Long.valueOf(o1.getId()).compareTo(Long.valueOf(o2.getId())) > 0 ? o1 : o2));

输出结果为:[满300减30, 满300赠25, 买180赠10]

参考

免责声明:文章转载自《Java8 stream分组按某字段取最大值》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇关于vue的页面跳转后,如何每次进入页面时都能获取后台数据重啓ubuntu后 VNC 自動運行下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

MySQL学习笔记:字符串前后补全0

遇到一个要求:如果位数小于6,则需要使用函数LPAD()和RPAD()自动完成6位。LPAD使用字符串padstr填充并完成左侧的str,直到其长度达到len个字符,并返回str。...

5G中的频点计算及实例分析

相关图表:关于∏SSB的频域位置SSREF和GSCN之间的关系,请参见下表:注:SCSspacedchannelrasterisM=3的工作频带的默认值。同步网格是5G的第一个概念,旨在加快终端扫描SSB的频率位置。GSCN通常用于在SA联网模式下加速时频同步,以继续解释MIB和SIB1消息;对于NSA来说,这是不必要的。RRC重配置消息已经携带了NR的SS...

2022年可用QQ机器人框架

4.小李子机器人官网:https://xiaolz.cn评估:支持多个Q登录和论坛似乎是目前最活跃的。它支持许多api,可以满足许多需求。没有限制,但有很多错误。...

数据库软考易混淆知识之信息化基础、项目管理

2、 关键路径关键路径是活动图中最长的路径示例:图中显示了软件项目的活动图,其中固定点表示项目里程碑,连接顶点的边表示包含的活动,边上的数字表示活动持续时间的天数,则完成项目的最短时间为()天,活动EH和IJ的放松时间分别为()日。...

图卷积神经网络(GCN)入门

不得不专门为GCN开一个新篇章,表示其重要程度。图卷积神经网络,实际上跟CNN的作用一样,就是一个特征提取器,只不过它的对象是图数据。总地来说,图数据既要考虑节点信息,也要考虑结构信息,图卷积神经网络就可以自动化地既学习节点特征,又能学习节点与节点之间的关联信息。GCN的本质目的就是用来提取拓扑图的空间特征。理解图卷积神经网络主要有两类,一类是基于空间域或顶...

WebSocket 详解教程

WebSocket是一种网络通信协议。由于WebSockets连接存在很长时间,它与典型的HTTP连接不同,对服务器有重要影响。WebSocket事件以下是WebSocket对象的相关事件。其中,Tomcat 7、Jetty 7及以上版本开始支持WebSocket。此外,Spring框架还提供对WebSocket的支持。尽管如此,上述应用程序有自己的WebS...