Java Comparator自定义排序:保留特定值对象的原始位置
自定义Comparator排序问题:保留-1值元素原始位置,其余降序排列
需求描述
对Candidate对象列表排序,规则为:
- 值为-1的对象保留原始位置
- 其余对象按值降序排列
输入示例
Candidate candidate1 = new Candidate("id1", 0.4); Candidate candidate2 = new Candidate("id2", -1.0); Candidate candidate3 = new Candidate("id3", 0.8); List<Candidate> inputCandidates = ImmutableList.of(candidate1, candidate2, candidate3);
期望输出
[ Candidate(super=Candidate(id=id3), value=0.8), Candidate(super=Candidate(id=id2), value=-1.0), Candidate(super=Candidate(id=id1), value=0.4) ]
当前实现代码
public final Comparator<Candidate> customComparator() { return (Candidate one, Candidate two) -> { double scoreOne = one.getValue() != null ? one.getValue() : 0d; double scoreTwo = two.getValue() != null ? two.getValue() : 0d; if (scoreOne == scoreTwo) return 0; if (scoreOne == -1.0d) return 1; if (scoreTwo == -1.0d) return -1; return Double.compare(scoreTwo, scoreOne); }; }
实际输出
[ Candidate(super=Candidate(id=id3), value=0.8), Candidate(super=Candidate(id=id1), value=0.4), Candidate(super=Candidate(id=id2), value=-1.0) ]
错误原因
你的Comparator逻辑无法实现需求——标准Comparator仅通过元素两两比较确定相对顺序,无法记录元素的原始索引,自然没法保留特定元素的原始位置。
当前代码中,只要遇到值为-1的元素,会强制将其往后排(和非-1元素比较时,-1元素会被判定为"更大",所以排序后移到末尾),这完全违背了"保留原始位置"的要求。
解决方案
要实现需求,必须结合元素的原始索引来排序,步骤如下:
- 将每个
Candidate与它的原始索引绑定(用现成的AbstractMap.SimpleEntry或自定义类); - 对绑定后的列表排序:
- 若两个元素都是-1值,按原始索引升序保留相对位置;
- 若其中一个是-1值,按原始索引升序排列,确保-1元素留在原位置;
- 若都不是-1值,按score降序排列;
- 提取排序后的
Candidate对象,得到最终列表。
示例代码
import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; public class CandidateSorter { public static List<Candidate> sortWithMinus1Retained(List<Candidate> input) { // 绑定元素与原始索引 List<Map.Entry<Candidate, Integer>> indexedCandidates = IntStream.range(0, input.size()) .mapToObj(index -> new AbstractMap.SimpleEntry<>(input.get(index), index)) .collect(Collectors.toList()); // 自定义排序逻辑 indexedCandidates.sort((entry1, entry2) -> { Candidate c1 = entry1.getKey(); Candidate c2 = entry2.getKey(); double score1 = c1.getValue() != null ? c1.getValue() : 0d; double score2 = c2.getValue() != null ? c2.getValue() : 0d; boolean isC1Minus1 = score1 == -1.0d; boolean isC2Minus1 = score2 == -1.0d; if (isC1Minus1 && isC2Minus1) { // 两个都是-1,按原始索引升序保留相对位置 return Integer.compare(entry1.getValue(), entry2.getValue()); } else if (isC1Minus1 || isC2Minus1) { // 其中一个是-1,按原始索引升序,确保原位置不变 return Integer.compare(entry1.getValue(), entry2.getValue()); } else { // 都不是-1,按score降序排列 return Double.compare(score2, score1); } }); // 提取排序后的Candidate对象 return indexedCandidates.stream() .map(Map.Entry::getKey) .collect(Collectors.toList()); } }
调用该方法后,输入示例列表将得到你期望的输出结果。
内容的提问来源于stack exchange,提问作者Prathamesh Mahankal
相关产品推荐
相关产品推荐

