如何根据InputObject的ascending字段条件控制流的多阶排序顺序?
问题描述
现有一段用于动态选择并链式调用比较器的代码:
class InputObject { String inputName; boolean ascending; // 注:原代码中写成String,结合示例应为布尔类型笔误 } Map<String, Comparator<OutputObject>> comparatorsMap = .... // 用于动态获取对应字段的比较器 List<InputObject> input = Arrays.asList(new InputObject("hello", true), new InputObject("goodbye", false)); Comparator<OutputObject> comparator = input.stream() .map(comparatorsMap::get) .reduce(Comparator::thenComparing) .orElse((a, b) -> 0); List<OutputObject> sorted = dataCollection.stream().sorted( comparator ).collect( Collectors.toList() );
需求是利用InputObject中的ascending字段,对每个对应的比较器单独判断是否反转排序顺序,每个输入对象的排序方向独立。
举个示例:
输入排序规则为[ {"byName", false}, {"byID", true} ],未排序数据:
OutputObject=("Mike", 5) OutputObject=("Bob", 4) OutputObject=("Mike", 1)
处理流程:
- 先按名称排序得到:
OutputObject=("Bob", 4) OutputObject=("Mike", 5) OutputObject=("Mike", 1)
- 因
byName的ascending=false,反转这一步的排序结果:
OutputObject=("Mike", 5) OutputObject=("Mike", 1) OutputObject=("Bob", 4)
- 再对名称相同的元素按ID升序排序(
ascending=true),最终得到:
OutputObject=("Mike", 1) OutputObject=("Mike", 5) OutputObject=("Bob", 4)
之前尝试在map的lambda中保存布尔字段,但不确定如何在流操作中条件性反转对应比较器的顺序。
解决方案
核心思路是对每个InputObject先根据ascending字段调整对应比较器(反转或保持原顺序),再将调整后的比较器链式组合,而非先组合再反转(那样会反转整个排序逻辑,不符合单字段独立控制的需求)。
修改后的代码如下:
Comparator<OutputObject> comparator = input.stream() // 逐个处理InputObject,调整对应比较器的排序方向 .map(inputObj -> { Comparator<OutputObject> baseComparator = comparatorsMap.get(inputObj.inputName); // 根据ascending字段决定是否反转当前比较器 return inputObj.ascending ? baseComparator : baseComparator.reversed(); }) // 链式拼接所有调整后的比较器 .reduce(Comparator::thenComparing) // 空输入时返回默认比较器,避免空指针 .orElse((a, b) -> 0); List<OutputObject> sorted = dataCollection.stream() .sorted(comparator) .collect(Collectors.toList());
逻辑说明
- 单比较器调整:在
map阶段,每个InputObject对应的比较器都会被单独处理——如果ascending为false,调用Comparator.reversed()反转该字段的排序方向;为true则直接使用原比较器。 - 链式组合:通过
reduce(Comparator::thenComparing)将所有调整后的比较器按输入顺序拼接,实现多字段优先级排序。 - 边界处理:
orElse提供默认的空比较器,避免输入列表为空时抛出NullPointerException。
示例验证
针对示例中的规则[ {"byName", false}, {"byID", true} ]:
- 处理
byName比较器:因ascending=false,得到byNameComparator.reversed(); - 处理
byID比较器:因ascending=true,直接使用byIDComparator; - 最终组合的比较器逻辑为:先按名称降序排序,名称相同时按ID升序排序,完全匹配示例的预期结果。
注意事项
- 确保
comparatorsMap中存在InputObject.inputName对应的Comparator,可在map中加入空值校验,比如Objects.requireNonNull(baseComparator, "未找到对应字段的比较器:" + inputObj.inputName); - 原代码中
InputObject的ascending字段定义为String,建议改为boolean类型,避免字符串转布尔值的额外处理。
内容的提问来源于stack exchange,提问作者pleasedontbemeantome
相关产品推荐
相关产品推荐

