java - java - 如何对列表进行排序并使用其更改的索引对Java中的另一个列表进行排序?
问题描述
我有 3 个列表:
ArrayList<Integer> at = new ArrayList<>(Arrays.asList(2, 0, 2, 3, 4));
ArrayList<Integer> bt = new ArrayList<>(Arrays.asList(2, 1, 3, 5, 4));
ArrayList<String> prc = new ArrayList<>(Arrays.asList("p1", "p2", "p3", "p4", "p5"));
如果我排序at
,我会得到[0, 2, 2, 3, 4
]。
我想要两者bt
并prc
遵循这种模式。即:bt =[1, 2, 3, 5, 4]
和
prc=["p2", "p1", "p3", "p4", "p5"]
。由于在at
排序时索引 1 与索引 2 交换,我希望其他 2 个数组也发生同样的事情。
我尝试在 Python 中实现它。这很容易,因为如果值在数据框中,对一列进行排序将自动给出所需的结果。我不能在 Java 中做同样的事情。
解决方案
方法一(先提取索引,构造新列表)
如果您可以更改数据格式并使用自定义对象,我建议使用方法 2。
您可以先将原始元素的索引提取at
到一个数组sortedIndices
中。如果列表已经排序,则值为[1, 2, 3, ..., n-1]
. 如果需要交换前两个元素,则值为[1, 0, 2, 3, ..., n-1]
. 之后,您可以通过根据存储的位置添加元素来构造和填充两个排序列表 ( btSorted
/ ) 。prcSorted
sortedIndices[i]
ArrayList<Integer> at = new ArrayList<>(Arrays.asList(2, 0, 2, 3, 4));
ArrayList<Integer> bt = new ArrayList<>(Arrays.asList(2, 1, 3, 5, 4));
ArrayList<String> prc = new ArrayList<>(Arrays.asList("p1", "p2", "p3", "p4", "p5"));
// get indexes of a sorted 'at' list
int[] sortedIndices = IntStream.range(0, at.size())
.boxed().sorted(Comparator.comparing(at::get))
.mapToInt(x -> x).toArray();
// sort 'bt' according to 'at'
ArrayList<Integer> btSorted = new ArrayList<>();
for (int i = 0; i < sortedIndices.length; i++) {
btSorted.add(bt.get(sortedIndices[i]));
}
// sort 'prc' according to 'at'
ArrayList<String> prcSorted = new ArrayList<>();
for (int i = 0; i < sortedIndices.length; i++) {
prcSorted.add(prc.get(sortedIndices[i]));
}
// sort 'at' directly (just for inspection)
ArrayList<Integer> atSorted = new ArrayList<>(at);
Collections.sort(atSorted);
System.out.println("idx: " + Arrays.toString(sortedIndices));
System.out.println("at: " + at + " => " + atSorted);
System.out.println("bt: " + bt + " => " + btSorted);
System.out.println("prc: " + prc + " => " + prcSorted);
输出:
idx: [1, 0, 2, 3, 4]
at: [2, 0, 2, 3, 4] => [0, 2, 2, 3, 4]
bt: [2, 1, 3, 5, 4] => [1, 2, 3, 5, 4]
prc: [p1, p2, p3, p4, p5] => [p2, p1, p3, p4, p5]
方法2 (自定义类和Comparator
)
更具可读性的是将数据存储在自定义类中(例如DataEntry
)。然后,您可以轻松地对对象数组(例如data
)进行排序,而无需使用难以阅读的代码:
ArrayList<DataEntry> data = new ArrayList<>();
data.add(new DataEntry(2, 2, "p1"));
data.add(new DataEntry(0, 1, "p2"));
data.add(new DataEntry(2, 3, "p3"));
data.add(new DataEntry(3, 5, "p4"));
data.add(new DataEntry(4, 4, "p5"));
// sort data by 'at'
data.sort(Comparator.comparing(d -> d.at));
// print result
data.forEach(d -> System.out.println(d.at + ", " + d.bt + ", " + d.prc));
输出:
0, 1, p2
2, 2, p1
2, 3, p3
3, 5, p4
4, 4, p5
DataEntry
参考类:
static class DataEntry {
int at;
int bt;
String prc;
public DataEntry(int at, int bt, String prc) {
this.at = at;
this.bt = bt;
this.prc = prc;
}
}
方法 3 (使用indexOf
和Comparator
)
这仅在要排序的列表中没有重复项(bt
/ prc
)时才稳定,因为indexOf
始终返回列表中指定元素的第一次出现的索引(或 -1)。
可以使用自定义Comparator
和对列表进行排序indexOf
。我们可以在其他列表 ( / ) 中引用at
当前被比较元素 ( ) 的相应位置的值,以便对它们进行排序:d
bt
prc
ArrayList<Integer> at = new ArrayList<>(Arrays.asList(2, 0, 2, 3, 4));
ArrayList<Integer> bt = new ArrayList<>(Arrays.asList(2, 1, 3, 5, 4));
ArrayList<String> prc = new ArrayList<>(Arrays.asList("p1", "p2", "p3", "p4", "p5"));
// sort 'bt' according to 'at'
ArrayList<Integer> btSorted = new ArrayList<>(bt);
btSorted.sort(Comparator.comparing(d -> at.get(bt.indexOf(d))));
// sort prc according to 'at'
ArrayList<String> prcSorted = new ArrayList<>(prc);
prcSorted.sort(Comparator.comparing(d -> at.get(prc.indexOf(d))));
// sort 'at' (just for inspection)
ArrayList<Integer> atSorted = new ArrayList<>(at);
Collections.sort(atSorted);
// print result
System.out.println(at + " => " + atSorted);
System.out.println(bt + " => " + btSorted);
System.out.println(prc + " => " + prcSorted);
输出:
at: [2, 0, 2, 3, 4] => [0, 2, 2, 3, 4]
bt: [2, 1, 3, 5, 4] => [1, 2, 3, 5, 4]
prc: [p1, p2, p3, p4, p5] => [p2, p1, p3, p4, p5]
推荐阅读
- vba - 有没有办法在 mac 上正确运行 vba 代码访问?
- javascript - Rails 6无限滚动未捕获ReferenceError:未定义InfiniteScroll
- css - 用 CSS3 为我的文本设置动画后,为什么它没有完全消失?
- python - 如何从 HTML 页面(与 Django 一起)调用带有参数的 Python 函数?
- r - 使用 Rvest 和 Glue 从网页抓取多个页面中创建聚合 df
- winapi - MFC:在 CWnd::OnCreate() 之后保证调用什么?
- r - 在R中添加一个系列作为列
- c# - 为什么我不能在 C# 中读取此注册表项
- r - 为什么将字符更改为日期格式会给我 NA 值?
- python - 旋转后的OpenGL python和pygame翻译不适用于mouselook和移动