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

如何对PriceRow列表按productCode分组后排序并取首元素?

嘿,你的现有方案已经能很好地解决问题了!不过咱们可以借助Java Stream的排序API来简化代码,让整个逻辑更紧凑、可读性更强,一起来梳理下并看看优化方案吧~

问题背景

我们有一批PriceRow(productCode, key, sector)类型的对象列表:

List<PriceRow> priceRowList = new ArrayList<>(); 
priceRowList.add(new PriceRow("10kgbag","", "SECTOR"));
priceRowList.add(new PriceRow("10kgbag","12345", ""));
priceRowList.add(new PriceRow("10kgbag","", ""));
priceRowList.add(new PriceRow("20kgbag","", "SECTOR"));
priceRowList.add(new PriceRow("20kgbag","12345", ""));
priceRowList.add(new PriceRow("20kgbag","", ""));
priceRowList.add(new PriceRow("30kgbag","", "SECTOR"));
priceRowList.add(new PriceRow("30kgbag","", ""));
priceRowList.add(new PriceRow("40kgbag","", ""));
priceRowList.add(new PriceRow("50kgbag","", ""));

核心需求

按productCode对列表分组,分组内的排序优先级为:

  1. key非空的元素优先
  2. 若key都为空,则sector非空的元素优先
  3. 最后选取key和sector都为空的元素
    最终取每组排序后的首个元素生成Map<String, PriceRow>

预期断言验证

assertEquals("12345",map.get("10kgbag").getFlightKey()); 
assertEquals("12345",map.get("20kgbag").getFlightKey()); 
assertEquals("SECTOR",map.get("30kgbag").getSector()); 
assertEquals("",map.get("40kgbag").getFlightKey()); 
assertEquals("",map.get("50kgbag").getFlightKey()); 

现有解决方案

import org.apache.commons.lang.StringUtils; 
import java.util.List; 
import java.util.Map; 
import java.util.stream.Collectors; 

public class Example { 
    public Map<String,PriceRow> evaluate(List<PriceRow> priceRowList) { 
        Map<String,PriceRow> map = priceRowList.stream() 
            .collect(Collectors.groupingBy(priceRow -> priceRow.getProductCode(), 
                Collectors.collectingAndThen(Collectors.toList(), value -> getMostEligibleValue(value)))); 
        return map; 
    } 

    private PriceRow getMostEligibleValue(List<PriceRow> priceRowList){ 
        for(PriceRow priceRowWithKey : priceRowList) 
            if(StringUtils.isNotBlank(priceRowWithKey.getKey())) 
                return priceRowWithKey; 
        for(PriceRow priceRowWithSector : priceRowList) 
            if(StringUtils.isNotBlank(priceRowWithSector.getSector())) 
                return priceRowWithSector; 
        return priceRowList.stream().findFirst().get(); 
    } 
} 

更优解决方案

我们可以直接在Stream流水线中通过自定义排序逻辑实现需求,避免额外的循环方法,让逻辑更连贯:

import org.apache.commons.lang.StringUtils;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Example {
    public Map<String, PriceRow> evaluate(List<PriceRow> priceRowList) {
        // 定义排序规则:key非空优先 → sector非空优先
        Comparator<PriceRow> eligibilityComparator = Comparator
                .comparing((PriceRow pr) -> StringUtils.isBlank(pr.getKey())) // key非空的元素会返回false,排序更靠前
                .thenComparing(pr -> StringUtils.isBlank(pr.getSector())); // 同理,sector非空的元素更靠前

        return priceRowList.stream()
                .collect(Collectors.groupingBy(
                        PriceRow::getProductCode,
                        // 分组后按规则排序,取优先级最高的第一个元素
                        Collectors.collectingAndThen(
                                Collectors.minBy(eligibilityComparator),
                                // 业务场景下分组不会为空,用orElseThrow抛出明确异常替代get()
                                opt -> opt.orElseThrow(() -> new IllegalArgumentException("Empty group for product code"))
                        )
                ));
    }
}

优化点说明

  • 逻辑更紧凑:把排序和选取逻辑整合到Stream流水线中,无需额外遍历方法
  • 可读性更强:通过Comparator链式调用清晰表达排序优先级,规则一目了然
  • 更贴合Stream风格:利用Collectors.minBy获取排序后的首个元素(符合条件的元素比较值更小,所以min就是优先元素)
  • 安全性提升:用orElseThrow替代get(),若出现空分组(业务中大概率不会)会抛出明确异常,避免模糊的NoSuchElementException

如果你的项目使用Java 11+,还可以用JDK自带的String.isBlank()替代Apache Commons的工具类,减少第三方依赖:

// Java 11+ 可使用的比较器
Comparator<PriceRow> eligibilityComparator = Comparator
        .comparing((PriceRow pr) -> pr.getKey().isBlank())
        .thenComparing(pr -> pr.getSector().isBlank());

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:13:09