I have an array of objects called array and have 3 items in it, which are: id, numAccess and numDelete (all in primitive int).
What I want to do: 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);
}
Let's say if before sort
is this:
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
Then desired after sort
should be:
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
However, what I get is this:
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
I couldn't figure out what's wrong. May I get some advice? Thank you very much.
CodePudding user response:
It seems the input array contains several "empty" Process
values (with ID == 0
), so sorting needs to be customized to put such values to the end of array, or the input array needs to be filtered to exclude such values.
- Put to the end the values with
ID == 0
A method to customize process id for sorting needs to be implemented:
// MyClass
public static int getIdForSorting(Process p) {
return p.getId() == 0 ? Integer.MAX_VALUE : 0;
}
Then it may be used in sorting:
Arrays.sort(array, Comparator
.comparingInt(MyClass::getIdForSorting)
.thenComparingInt(Process::getNumAccess)
.thenComparingInt(Process::getNumDelete)
);
When printing the array contents using for
loop, indexing has to start from 0.
for (int i = 0; i < n; i ) {
System.out.println(arr[i]); // assuming method `toString` overridden in Process
}
- Use Stream API to filter out "empty" processes
Process[] sortedArray = Arrays.stream(array)
.filter(p -> p.getId() > 0)
.sorted(Comparator
.comparingInt(Process::getNumAccess)
.thenComparingInt(Process::getNumDelete)
)
.toArray(Process[]::new);
Here "empty" values are truncated after sorting, so for-each
loop may be used:
for (Process process : sortedArray) {
System.out.println(process); // assuming method `toString` overridden in Process
}
@ThomasKläger offered an interesting solution based on Arrays::sort(T[] arr, int from, int to, Comparator<T> comparator)
method to sort the array in range [1..n 1]
.
In this case item[0] and the tail of the array remains unsorted.
Tests:
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
CodePudding user response:
If you want to only sort part of the array (from index 1 to n inclusive) you can use Arrays.sort(array, 1, n 1, comparator);
Also note that your comparator implementation is unnecessarily complex. You can replace
Integer compr = Integer.valueOf(p1.numAccess).compareTo(Integer.valueOf(p2.numAccess));
with
int compr = Integer.compare(p1.numAccess, p2.numAccess));
CodePudding user response:
If you're using Java 8, you can use method Comparator::comparing
to start sorting on first field and then a chain of Comparator::thenComparing
methods to choose the subsequent fields to sort on
Comparator<Process> processComparator = Comparator.comparing(Process::getNumAccess)
.thenComparing(Process::numDelete);
Arrays.sort(array, processComparator);
CodePudding user response:
Assuming your class has accessors for the fields, you can use Comparator#comparing methods to simplify your comparator logic.
Arrays.sort(array, Comparator.comparingInt(Array::getNumAccess)
.thenComparingInt(Array::getNumDelete));
Also, note that array indices start at 0 and hence your for loop should be like,
for (int i = 0; i < n; i ) {
System.out.println("ID: " array[i].id " numAccess: " array[i].numAccess " numDelete: " array[i].numDelete);
}