Java 比较器问题(比较两次)
Java Comparator Issue (Compare twice)
我有一个名为数组的对象数组,其中有 3 个项目,它们是:id、numAccess 和 numDelete (全部为原始整数)。
我想做什么:sort first by numAccess then by numDelete
.
for(int i=1; i<=n; i++){
System.out.println("ID: " + array[i].id + " numAccess: " + array[i].numAccess + " numDelete: " + array[i].numDelete);
}
Arrays.sort(array, new Comparator<Process>(){
public int compare(Process p1, Process p2) {
Integer compr = Integer.valueOf(p1.numAccess).compareTo(Integer.valueOf(p2.numAccess));
if (compr != 0) {
return compr;
}
return Integer.valueOf(p1.numDelete).compareTo(Integer.valueOf(p2.numDelete));
}
});
for(int i=1; i<=n; i++){
System.out.println("ID: " + array[i].id + " numAccess: " + array[i].numAccess + " numDelete: " + array[i].numDelete);
}
假设 before sort
是这样的:
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 4 numAccess: 13 numDelete: 5
ID: 5 numAccess: 9 numDelete: 13
ID: 6 numAccess: 0 numDelete: 6
那么desired after sort
应该是:
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 5 numAccess: 9 numDelete: 13
ID: 4 numAccess: 13 numDelete: 5
然而,我得到的是:
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
我不知道出了什么问题。我可以得到一些建议吗?非常感谢。
如果你只想对数组的一部分进行排序(从索引 1 到 n),你可以使用 Arrays.sort(array, 1, n+1, comparator);
另请注意,您的比较器实现过于复杂。你可以替换
Integer compr = Integer.valueOf(p1.numAccess).compareTo(Integer.valueOf(p2.numAccess));
与
int compr = Integer.compare(p1.numAccess, p2.numAccess));
假设您的 class 具有 字段访问器 ,您可以使用 Comparator#comparing methods 来简化比较器逻辑。
Arrays.sort(array, Comparator.comparingInt(Array::getNumAccess)
.thenComparingInt(Array::getNumDelete));
此外,请注意数组索引从 0 开始,因此您的 for 循环应该像,
for (int i = 0; i < n; i++) {
System.out.println("ID: " + array[i].id + " numAccess: " + array[i].numAccess + " numDelete: " + array[i].numDelete);
}
如果您正在使用 Java 8,您可以使用方法 Comparator::comparing
开始对第一个字段进行排序,然后使用一系列 Comparator::thenComparing
方法来选择后续字段进行排序在
Comparator<Process> processComparator = Comparator.comparing(Process::getNumAccess)
.thenComparing(Process::numDelete);
Arrays.sort(array, processComparator);
似乎输入数组包含几个“空”Process
值(ID == 0
),因此需要自定义排序以将这些值放在数组末尾,或输入数组需要过滤以排除此类值。
- 将带有
ID == 0
的值放在最后
需要实现自定义进程id排序的方法:
// MyClass
public static int getIdForSorting(Process p) {
return p.getId() == 0 ? Integer.MAX_VALUE : 0;
}
那么在排序时可能会用到:
Arrays.sort(array, Comparator
.comparingInt(MyClass::getIdForSorting)
.thenComparingInt(Process::getNumAccess)
.thenComparingInt(Process::getNumDelete)
);
使用for
循环打印数组内容时,索引必须从0开始。
for (int i = 0; i < n; i++) {
System.out.println(arr[i]); // assuming method `toString` overridden in Process
}
- 使用 Stream API 过滤掉“空”进程
Process[] sortedArray = Arrays.stream(array)
.filter(p -> p.getId() > 0)
.sorted(Comparator
.comparingInt(Process::getNumAccess)
.thenComparingInt(Process::getNumDelete)
)
.toArray(Process[]::new);
此处“空”值在排序后被截断,因此可以使用for-each
循环:
for (Process process : sortedArray) {
System.out.println(process); // assuming method `toString` overridden in Process
}
@ThomasKläger 提供了一种 based on Arrays::sort(T[] arr, int from, int to, Comparator<T> comparator)
方法来对范围 [1..n+1]
.
中的数组进行排序
在这种情况下,项目 [0] 和数组的尾部保持未排序。
测试:
Process[] array = {
new Process(), new Process(1, 0, 8), new Process(2, 4, 15),
new Process(3, 7, 9), new Process(4, 13, 5), new Process(5, 9, 13),
new Process(6, 0, 6), new Process(), new Process()
};
// after sorting with getIdForSorting
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 5 numAccess: 9 numDelete: 13
ID: 4 numAccess: 13 numDelete: 5
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0
// after filtering/truncating
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 5 numAccess: 9 numDelete: 13
ID: 4 numAccess: 13 numDelete: 5
// after sorting the subrange
ID: 0 numAccess: 0 numDelete: 0
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 5 numAccess: 9 numDelete: 13
ID: 4 numAccess: 13 numDelete: 5
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0
我有一个名为数组的对象数组,其中有 3 个项目,它们是:id、numAccess 和 numDelete (全部为原始整数)。
我想做什么:sort first by numAccess then by numDelete
.
for(int i=1; i<=n; i++){
System.out.println("ID: " + array[i].id + " numAccess: " + array[i].numAccess + " numDelete: " + array[i].numDelete);
}
Arrays.sort(array, new Comparator<Process>(){
public int compare(Process p1, Process p2) {
Integer compr = Integer.valueOf(p1.numAccess).compareTo(Integer.valueOf(p2.numAccess));
if (compr != 0) {
return compr;
}
return Integer.valueOf(p1.numDelete).compareTo(Integer.valueOf(p2.numDelete));
}
});
for(int i=1; i<=n; i++){
System.out.println("ID: " + array[i].id + " numAccess: " + array[i].numAccess + " numDelete: " + array[i].numDelete);
}
假设 before sort
是这样的:
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 4 numAccess: 13 numDelete: 5
ID: 5 numAccess: 9 numDelete: 13
ID: 6 numAccess: 0 numDelete: 6
那么desired after sort
应该是:
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 5 numAccess: 9 numDelete: 13
ID: 4 numAccess: 13 numDelete: 5
然而,我得到的是:
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
我不知道出了什么问题。我可以得到一些建议吗?非常感谢。
如果你只想对数组的一部分进行排序(从索引 1 到 n),你可以使用 Arrays.sort(array, 1, n+1, comparator);
另请注意,您的比较器实现过于复杂。你可以替换
Integer compr = Integer.valueOf(p1.numAccess).compareTo(Integer.valueOf(p2.numAccess));
与
int compr = Integer.compare(p1.numAccess, p2.numAccess));
假设您的 class 具有 字段访问器 ,您可以使用 Comparator#comparing methods 来简化比较器逻辑。
Arrays.sort(array, Comparator.comparingInt(Array::getNumAccess)
.thenComparingInt(Array::getNumDelete));
此外,请注意数组索引从 0 开始,因此您的 for 循环应该像,
for (int i = 0; i < n; i++) {
System.out.println("ID: " + array[i].id + " numAccess: " + array[i].numAccess + " numDelete: " + array[i].numDelete);
}
如果您正在使用 Java 8,您可以使用方法 Comparator::comparing
开始对第一个字段进行排序,然后使用一系列 Comparator::thenComparing
方法来选择后续字段进行排序在
Comparator<Process> processComparator = Comparator.comparing(Process::getNumAccess)
.thenComparing(Process::numDelete);
Arrays.sort(array, processComparator);
似乎输入数组包含几个“空”Process
值(ID == 0
),因此需要自定义排序以将这些值放在数组末尾,或输入数组需要过滤以排除此类值。
- 将带有
ID == 0
的值放在最后 需要实现自定义进程id排序的方法:
// MyClass
public static int getIdForSorting(Process p) {
return p.getId() == 0 ? Integer.MAX_VALUE : 0;
}
那么在排序时可能会用到:
Arrays.sort(array, Comparator
.comparingInt(MyClass::getIdForSorting)
.thenComparingInt(Process::getNumAccess)
.thenComparingInt(Process::getNumDelete)
);
使用for
循环打印数组内容时,索引必须从0开始。
for (int i = 0; i < n; i++) {
System.out.println(arr[i]); // assuming method `toString` overridden in Process
}
- 使用 Stream API 过滤掉“空”进程
Process[] sortedArray = Arrays.stream(array)
.filter(p -> p.getId() > 0)
.sorted(Comparator
.comparingInt(Process::getNumAccess)
.thenComparingInt(Process::getNumDelete)
)
.toArray(Process[]::new);
此处“空”值在排序后被截断,因此可以使用for-each
循环:
for (Process process : sortedArray) {
System.out.println(process); // assuming method `toString` overridden in Process
}
@ThomasKläger 提供了一种 Arrays::sort(T[] arr, int from, int to, Comparator<T> comparator)
方法来对范围 [1..n+1]
.
在这种情况下,项目 [0] 和数组的尾部保持未排序。
测试:
Process[] array = {
new Process(), new Process(1, 0, 8), new Process(2, 4, 15),
new Process(3, 7, 9), new Process(4, 13, 5), new Process(5, 9, 13),
new Process(6, 0, 6), new Process(), new Process()
};
// after sorting with getIdForSorting
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 5 numAccess: 9 numDelete: 13
ID: 4 numAccess: 13 numDelete: 5
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0
// after filtering/truncating
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 5 numAccess: 9 numDelete: 13
ID: 4 numAccess: 13 numDelete: 5
// after sorting the subrange
ID: 0 numAccess: 0 numDelete: 0
ID: 6 numAccess: 0 numDelete: 6
ID: 1 numAccess: 0 numDelete: 8
ID: 2 numAccess: 4 numDelete: 15
ID: 3 numAccess: 7 numDelete: 9
ID: 5 numAccess: 9 numDelete: 13
ID: 4 numAccess: 13 numDelete: 5
ID: 0 numAccess: 0 numDelete: 0
ID: 0 numAccess: 0 numDelete: 0