2016-11-12 54 views
0

我试图使用接口比较器来订购一个优先队列,这样如果乘客的订单有残疾,他们的订单就取决于第一个订单,然后取决于他们有的票的类型以及最后的到达时间。如何将Comparator与多个字段对象一起使用?

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; 
    } 

} 

有我初始化乘客的阵列,这里是头等舱乘客和比较方法:

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 
     } 
    } 
} 

我该如何处理以更好的方式,这些多层次的比较?

+1

所以具体是什么问题呢?代码是否会抛出错误?它排序不正确吗? – Keiwan

+0

你比较,你通过一个构造函数的参数为​​空 – Rogue

回答

0

看来你的问题是关于简化您的比较,但我认为你宁愿实现Comparable<Passenger>而不是Comparator,并使用#compareTo方法。至于清理,这是一个有点一件容易的事,如果你只是抽象的实际布尔逻辑:

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 
} 

这允许你定义一个自然排序为Passenger,和封装/内部类实现(不需要尽可能多的曝光)。

这也使得像分拣更容易操作:

List<Passenger> passengers = /* some list */; 
Collections.sort(passengers); 

如果你想提供一个比较器,可以完成替代排序,你也可以做你的类中:

public class Passenger { 

    //... 

    public static class ArrivalComparator implements Comparator<Passenger> { 

     public int compare(Passenger one, Passenger two) { 
      return Integer.compare(one.getArrivalTime(), two.getArrivalTime()); 
     } 
    } 

    //... 

} 

使用我们前面的例子,这会让你根据到达时间对所有乘客进行分类:

Collections.sort(passengers, new Passenger.ArrivalComparator()); 

此外,这刚好可以使用Java 8联:

//Sort by arrival time 
Collections.sort(passengers, (one, two) -> Integer.compare(one.getArrivalTime(), two.getArrivalTime()); 

但总体而言,记住一个比较主要是定义一个特定的排序,而Comparable定义了通用/自然排序。

+0

你compareTo方法过于复杂,易于维护和其他选项将在一个时间只能做一个比较,如果你提到,他们需要一起使用才能达到预期这将是很好结果 – developer

+0

这并不太复杂,实际上我认为它比OP中最初的'#比较'更清晰。其他选项一次只能执行一项,但您可以根据自己的喜好对它们进行严格比较。它们并不一定需要一起使用,'#compareTo'可以用于大多数事物(包括'Collections#sort'和'PriorityQueue'的构造函数)的'Comparator'的就地,而我的要点是“比较器”应该是针对特定顺序而不是OP发布的自然顺序。 – Rogue

+0

嘿,非常感谢你使用你的代码并做了一些改变,只是看看我自己的回答,真的非常感谢你。 –

1

我想你在找什么是重构你的代码,我会建议分离compare逻辑到一个单独的PassengerComparator类(SRP)为更好地维护如下图所示可读性

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(); 
    } 
} 

用法:

PriorityQueue<Book> queue = new PriorityQueue<Book>(10, new PassengerComparator()); 
+0

岂不是'PassengerComparator实现比较'你会初始化为'PassengerComparator补偿=新PassengerComparator();'? – Rogue

+0

你是正确的,更新的使用 – developer

0

如何以更好的方式处理这些多级别的比较?

  1. 为每个属性创建单独的比较器。
  2. 将各个比较器组合成多级比较。有关此方法的示例,请查看Group Comparator

因此,知道你有可重复使用的代码,它允许你按照你希望的任何顺序进行排序,而无需编写复杂的多级比较器。

您可能还需要检查出的Bean Comparator这使得它很容易在一个单一的代码行创建单独的比较。

0

嘿,我刚刚得到正确的答案,只是通过增加这类客运它的作品了确切的方式,我想这样的优先顺序是:残疾,阶级和arrivalTime,太谢谢你了。 :)

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; 
} 
相关问题