Java中按一个ArrayList排序规则同步排序其他关联ArrayList的方法
多关联ArrayList同步排序解决方案
原有实现的问题
你当前的写法存在两个核心bug:
- 依赖
indexOf()反查元素位置,遇到重复值时只会返回首个匹配项的索引,完全无法对应元素的真实关联位置,排序结果必然错位 - 三次独立排序逻辑本身不成立:排序
scoreListNames和scoreListWords时,参考的是未排序的原始scoreListScores值,等两个列表排完再单独排序scoreListScores,哪怕没有重复元素,三者的对应关系也会混乱。
另外每次比较都调用indexOf()会全表遍历,列表稍长性能会极差。
问题1:排序时能否直接获取当前元素的真实索引
Collections.sort()自带的比较器入参只有待比较的元素本身,不会暴露当前元素的遍历索引,不要尝试在比较器里硬写逻辑找索引,属于绕远路还容易错的思路。
如果需要全程绑定索引做排序,直接操作索引列表是最直接的实现方式,不需要靠元素值反查位置。
问题2:无自定义类场景下的最优同步排序方案
受限于不能新建自定义类封装关联字段的要求,索引代理排序法是适配性最高、稳定性最好的方案,完全规避重复值问题,逻辑也最简单:
- 先校验三个列表长度一致,从根源避免非一一对应的异常
- 新建一个整数索引列表,按顺序存入0到列表长度-1的整数,每个整数对应三个列表同位置的一组关联数据
- 只对索引列表做排序,排序规则为:根据索引取
scoreListScores里对应的值做比较,全程不改动三个原列表的元素 - 索引排序完成后,按照新的索引顺序,把三个原列表的元素重新赋值排列,即可得到完全同步的排序结果
实现代码
// 基础校验 if (scoreListNames.size() != scoreListScores.size() || scoreListWords.size() != scoreListScores.size()) { throw new IllegalArgumentException("三个关联列表长度必须一致,无法一一对应"); } int size = scoreListScores.size(); // 生成代理索引列表 List<Integer> indexList = new ArrayList<>(size); for (int i = 0; i < size; i++) { indexList.add(i); } // 仅对索引列表按分数升序排序,要改降序直接调整比较器即可 indexList.sort(Comparator.comparingInt(scoreListScores::get)); // 如需降序,把上一行替换为: // indexList.sort(Comparator.comparingInt((Integer i) -> scoreListScores.get(i)).reversed()); // 拷贝原列表数据做临时源,避免重排时覆盖原值 List<String> tempNames = new ArrayList<>(scoreListNames); List<String> tempWords = new ArrayList<>(scoreListWords); List<Integer> tempScores = new ArrayList<>(scoreListScores); // 按排好的索引重排三个原列表 for (int i = 0; i < size; i++) { int targetIdx = indexList.get(i); scoreListNames.set(i, tempNames.get(targetIdx)); scoreListWords.set(i, tempWords.get(targetIdx)); scoreListScores.set(i, tempScores.get(targetIdx)); }
方案优势
- 完全不依赖元素值做关联匹配,哪怕分数、名称、单词全是重复值,也不会出现对应关系错乱的问题
- 只执行一次排序逻辑,性能远高于三次独立排序+每次全表查索引的写法
- 不需要新建自定义类,完全符合场景限制
- 排序规则调整非常方便,改索引列表的比较器即可,三个列表自动同步,不会出现逻辑不一致的问题
内容的提问来源于stack exchange,提问作者HMertAcr
相关产品推荐
相关产品推荐

