You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Condition列表对Promotion对象分组(Java 8 Collectors.groupingBy)

用Java 8 Collectors.groupingBy实现按Condition列表内容分组(第三方类不可修改)

完全可以实现,核心思路是为Collectors.groupingBy提供基于Condition列表内容的键提取逻辑,而非直接使用Criteria对象作为分组键。因为第三方类可能未正确实现equals()和hashCode(),我们需要自行构建能唯一标识Condition列表内容的分组键。

实现步骤

  1. 确定Condition的内容标识方式:

    • 如果第三方Condition类已经基于属性内容实现了正确的equals()和hashCode(),直接用其列表作为键即可。
    • 如果Condition的equals()/hashCode()是基于对象引用(而非内容),则需要提取Condition的所有关键属性,封装成自定义的键对象(或属性列表)来实现内容比对。
  2. 编写键提取函数:
    针对不同的Condition实现情况,编写对应的函数从Promotion中提取分组键。

  3. 执行分组:
    将键提取函数传入Collectors.groupingBy()完成分组。


代码示例

场景1:Condition已正确实现equals/hashCode

假设Condition类的equals()和hashCode()会比较属性内容,直接用Condition列表作为分组键:

// 定义键提取器:从Promotion中获取Condition列表
Function<Promotion, List<Condition>> groupingKey = promo -> 
    new ArrayList<>(promo.getCriteria().getConditions()); // 用ArrayList保证可序列化,或用ImmutableList.copyOf()

// 执行分组
Map<List<Condition>, List<Promotion>> groupedPromos = promotions.stream()
    .collect(Collectors.groupingBy(groupingKey));

场景2:Condition未正确实现equals/hashCode

此时需要自定义键对象,提取Condition的关键属性来实现内容比对:

// 自定义键类,基于Condition的属性实现equals和hashCode
class ConditionContentKey {
    private final String conditionType;
    private final int threshold;

    // 从Condition对象提取属性初始化
    public ConditionContentKey(Condition cond) {
        this.conditionType = cond.getType();
        this.threshold = cond.getThreshold();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ConditionContentKey that = (ConditionContentKey) o;
        return threshold == that.threshold && Objects.equals(conditionType, that.conditionType);
    }

    @Override
    public int hashCode() {
        return Objects.hash(conditionType, threshold);
    }
}

// 键提取器:将Condition列表转换为自定义键列表
Function<Promotion, List<ConditionContentKey>> groupingKey = promo -> 
    promo.getCriteria().getConditions().stream()
        .map(ConditionContentKey::new)
        .collect(Collectors.toList());

// 执行分组
Map<List<ConditionContentKey>, List<Promotion>> groupedPromos = promotions.stream()
    .collect(Collectors.groupingBy(groupingKey));

场景3:Condition列表顺序不影响分组

如果[condA, condB]和[condB, condA]需要归为同一组,需先对键列表排序:

Function<Promotion, List<ConditionContentKey>> sortedGroupingKey = promo -> 
    promo.getCriteria().getConditions().stream()
        .map(ConditionContentKey::new)
        .sorted(Comparator.comparing(ConditionContentKey::getConditionType)
                          .thenComparingInt(ConditionContentKey::getThreshold))
        .collect(Collectors.toList());

Map<List<ConditionContentKey>, List<Promotion>> groupedPromos = promotions.stream()
    .collect(Collectors.groupingBy(sortedGroupingKey));

验证预期结果

按照上述代码,你的测试场景会得到预期分组:

  • Grp1:promo1、promo3(Condition列表内容一致)
  • Grp2:promo2、promo4(Condition列表内容一致)
  • Grp3:promo5(Condition列表唯一)

内容的提问来源于stack exchange,提问作者net user

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 11:00:31