场景
项目中有这样的场景:
- 一个商品可以参与多个类型的促销活动,如满减、满赠、买赠、优惠券等活动;
- 相同类型的活动也可能有多个;
- 每个活动根据类型和具体的业务字段有一个活动标签,如满减活动,消费满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值更大
- 优惠券活动没有参与,因此没有该活动的促销标签
思路
- 将促销活动列表按促销活动类型分组生成一个map,其中key为促销活动类型,value为活动模型vo
- 将促销活动类型转为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]
参考
- java stream 处理分组后取每组最大 https://blog.csdn.net/weixin_30785593/article/details/96319304
- Java8 stream 之groupingBy() 分组排序 https://blog.csdn.net/wysnxzm/article/details/78930110