Reputation: 13
Im trying to use the interface comparator to order a priority queue so the oorder of the passengers depends in first levell if they have disability, then depending of the type of ticket they have and lastly the time of arrival.
import java.util.*;
public static void main(String[] args){
Random rand = new Random(System.nanoTime());
Comparator<Passenger> comparator;
PriorityQueue<Passenger> queue = new PriorityQueue<Passenger>(10, comparator);
Passenger pass[] = new Passenger [10];
for (int i=0; i<10;i++){
int time1 = 0;
pass[i] = new Passenger(rand.nextInt(100000000), rand.nextInt(3) , rand.nextBoolean(), time1);
time1 = time1 + 15;
}
}
There i initialize the array of passengers, here is the class Passenger and the compare method:
public class Passenger implements Comparator<Passenger>{
private int ID;
private int clase;
private boolean disability;
private int arrivalTime;
public Passenger(int ID, int clase, boolean disability, int arrivalTime) {
this.ID = ID;
this.clase = clase; // 0-vip 1-economy 2-economy
this.disability = disability;
this.arrivalTime = arrivalTime;
}
public int getID() {
return ID;
}
public void setID(int iD) {
ID = iD;
}
public int getClase() {
return clase;
}
public void setClase(int clase) {
this.clase = clase;
}
public boolean isDisability() {
return disability;
}
public void setDisability(boolean disability) {
this.disability = disability;
}
public int getArrivalTime() {
return arrivalTime;
}
public void setArrivalTime(int arrivalTime) {
this.arrivalTime = arrivalTime;
}
public int compare(Passenger pas1, Passenger pas2) {
if((pas1.isDisability()) && (!pas2.isDisability())){
return 1; //passenger 1 has disability
}else if((!pas1.isDisability()) && (pas2.isDisability())){
return -1; //passenger 2 has disability
}
else{ //both have disability or no one has disability
if(pas1.getClase() < pas2.getClase()){
return 1; // passenger 1 has better class
}else if(pas1.getClase() > pas2.getClase()){
return -1; // passenger 2 has better class
}
else{ //both have disability and same class
if(pas1.getArrivalTime() < pas2.getArrivalTime()){
return 1; //passenger 1 arrived before passenger 2
}
else return -1; //passenger 2 arrived before passenger 1
}
}
}
How can I handle these multi level comparisons in a better way ?
Upvotes: 1
Views: 1640
Reputation: 13
Hey I just get the right answer, just by adding this to the class Passenger it works out the exact way i wanted so the preference order is: disability, class and arrivalTime, thank you so much. :)
public int compareTo(Passenger other) {
if (this.isDisability() ^ other.isDisability()) { // use an XOR so it only enters if one of them is true
return this.isDisability() ? -1 : 1;
}
int clase = -Integer.compare(this.getClase(), other.getClase());
if (clase == 0) {
return this.getArrivalTime() < other.getArrivalTime() ? -1 : 1;
}
return clase > 0 ? -1 : 1;
}
Upvotes: 0
Reputation: 324108
How can I handle these multi level comparisons in a better way ?
So know you have reusable code that allows you to do sorting in any order you wish without writing a complex multi level Comparator.
You may also want to check out the Bean Comparator which makes it easy to create individual Comparators in a single line of code.
Upvotes: 0
Reputation: 11483
It seems your question is in regards to simplifying your comparison, but I think you'd rather implement Comparable<Passenger>
rather than Comparator
, and use the #compareTo
method. As for cleanup, that's a bit easy too if you simply abstract the actual boolean logic:
public int compareTo(Passenger other) {
if (this.isDisability() ^ other.isDisability()) { //use an XOR
return this.isDisability() ? 1 : -1; //1 for us, -1 for other
}
//compare #getClase
int clase = -Integer.compare(this.getClase(), other.getClase()); //invert
if (clase == 0) {
//compare arrival times if clase is equal
//normalize to -1, 1 (0 excluded in OP)
return this.getArrivalTime() < other.getArrivalTime() ? 1 : -1;
}
return clase > 0 ? 1 : -1; //normalize to -1, 0, 1
}
This allows you to define a natural ordering to a Passenger
, and is encapsulated/internal to your class implementation (doesn't require as much exposure).
This also makes operations like sorting much easier:
List<Passenger> passengers = /* some list */;
Collections.sort(passengers);
If you want to provide a Comparator which can accomplish alternative sorts, you can also do that inside your class:
public class Passenger {
//...
public static class ArrivalComparator implements Comparator<Passenger> {
public int compare(Passenger one, Passenger two) {
return Integer.compare(one.getArrivalTime(), two.getArrivalTime());
}
}
//...
}
Using our previous example, this would let you sort all the passengers based on arrival time:
Collections.sort(passengers, new Passenger.ArrivalComparator());
Additionally, this can just be inlined using Java 8:
//Sort by arrival time
Collections.sort(passengers, (one, two) -> Integer.compare(one.getArrivalTime(), two.getArrivalTime());
But overall, keep in mind a Comparator is mostly for defining a specific sort, while Comparable
defines a general/natural ordering.
Upvotes: 1
Reputation: 22422
I think what you are looking for is refactoring your code, I would recommend separating compare
logic into a separate PassengerComparator
class (SRP) for better maintenance and readability as shown below.
public class PassengerComparator implements Comparator<Passenger> {
public int compare(Passenger pas1, Passenger pas2) {
//check the comparison of all
if(disabilityComparator(Passenger pas1, Passenger pas2)
&& arrivalTimeComparator(Passenger pas1, Passenger pas2)
&& claseComparator(Passenger pas1, Passenger pas2)) {
return 1;
} else {
return -1;
}
}
//compares only disability
private int disabilityComparator(Passenger pas1, Passenger pas2) {
return pas1.isDisability() - pas2.isDisability();
}
//compares only arrivalTime
private int arrivalTimeComparator(Passenger pas1, Passenger pas2) {
return pas1.getArrivalTime() - pas2.getArrivalTime();
}
//compares only clase
private int claseComparator(Passenger pas1, Passenger pas2) {
return pas1.getClase() - pas2.getClase();
}
}
Usage:
PriorityQueue<Book> queue = new PriorityQueue<Book>(10, new PassengerComparator());
Upvotes: 1