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


場景

項目中有這樣的場景:

  • 一個商品可以參與多個類型的促銷活動,如滿減、滿贈、買贈、優惠券等活動;
  • 相同類型的活動也可能有多個;
  • 每個活動根據類型和具體的業務字段有一個活動標簽,如滿減活動,消費滿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]

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM