【问题标题】:Sort a List using a comparator with multiple criteria. FIFO使用具有多个条件的比较器对列表进行排序。先进先出
【发布时间】:2019-10-21 21:23:33
【问题描述】:

我在排序列表时遇到问题,我完成了给定练习中的所有任务,但这对我来说意义不大,我想修复它。所以我有一个在排队等候的人的名单,比方说,一家药房。怀孕的人应该优先于所有人,其次是年龄>60岁的人。一切正常,除了年龄大于 60 的人先来的人落后于年龄大于 60 的人(我只需要它与 FIFO 规则一起工作,怀孕标准按预期工作)。

我首先使用compareTo() 方法对列表进行排序,然后使用我创建的外部比较器类。

public class Main {
    public static void main(String[] args) {

        List<Customer> pharmacyQueue = new ArrayList<>();
        CustomerComparator customerComparator = new CustomerComparator();

        pharmacyQueue.add(new Customer(25, false, "Przemek"));
        pharmacyQueue.add(new Customer(35, true, "Anita"));
        pharmacyQueue.add(new Customer(55, false, "Wiesława"));
        pharmacyQueue.add(new Customer(25, true, "Maryja"));
        pharmacyQueue.add(new Customer(85, false, "Halinka"));
        pharmacyQueue.add(new Customer(55, false, "Stasia"));
        pharmacyQueue.add(new Customer(20, true, "Marta"));
        pharmacyQueue.add(new Customer(65, false, "Bożenka"));
        pharmacyQueue.add(new Customer(75, false, "Paoasdo"));

        Collections.sort(pharmacyQueue); 
        Collections.sort(pharmacyQueue, customerComparator);

        System.out.println("Sorted queue: ");
        for (Customer c : pharmacyQueue){
            System.out.println(c);
        }

    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor

public class Customer implements Comparable<Customer> {
    private int age;
    private boolean isPregnant;
    private String name;

    public int compareTo(Customer o) {
        if (this.age > 60){
            return -1;
        }else if (this.age < 60){
            return 1;
        }
        return 0;
    }
public class CustomerComparator implements Comparator<Customer> {
    @Override
    public int compare(Customer o1, Customer o2) {


        if (o1.isPregnant() && !o2.isPregnant()){
            return -1;
        }
        if (o1.isPregnant() && o2.isPregnant()){
            return 1;
        }


        return 0;
    }
}

结果:

Sorted queue: 
Customer(age=35, isPregnant=true, name=Anita) //fine
Customer(age=25, isPregnant=true, name=Maryja) //fine
Customer(age=20, isPregnant=true, name=Marta) //fine
Customer(age=75, isPregnant=false, name=Paoasdo) //should be 6th
Customer(age=65, isPregnant=false, name=Bożenka) //should be 5th
Customer(age=85, isPregnant=false, name=Halinka) //should be 4th
Customer(age=25, isPregnant=false, name=Przemek) //fine
Customer(age=55, isPregnant=false, name=Wiesława) //fine
Customer(age=55, isPregnant=false, name=Stasia) //fine

【问题讨论】:

  • 我只看到打印了一个列表....
  • 两次排序时,第2次会破坏第1次结果...
  • 比较器总是自给自足的,为什么你认为比较器保持初始排序不变?
  • 您的比较器都不正确。当机器人怀孕时,怀孕的比较器不应该返回 1,而是 0。当两者处于相同的年龄范围时,年龄比较器应该返回 0。当然,您需要将两种比较方法合二为一:首先按怀孕进行比较,然后如果结果为 0,则按年龄进行比较。使用组合比较器对列表进行一次排序。
  • 无论何时编写比较器,都需要使其具有反射性(x == x)、可交换性(如果x &lt; y,则为y &gt; x)和关联性(如果x &lt; yy &lt; z,则x &lt; z) - 见docs.oracle.com/javase/8/docs/api/java/util/…

标签: java list sorting collections


【解决方案1】:

为此,您基本上需要两件事:

  1. stable sort algorithm,即不会干扰“相等”(就排序顺序而言)元素的顺序的算法
  2. 正确识别哪些元素“相等”的比较器
    • 这就是您的两个比较器都失败的地方 - 年龄比较器甚至不使用关于另一个对象的信息 (!!!),并且怀孕比较器有一个错误,认为两个怀孕的客户具有不同的优先级。李>

【讨论】:

    【解决方案2】:

    正如在 cmets 中指出的那样,对列表进行两次排序与仅使用第二次排序进行排序相同(只是速度较慢)。哦,还有许多种类,如 QuickSort 是不稳定的(重新排列绑定值),而其他如 MergeSort 是稳定的。

    您想组合比较器(或比较器和可比较)。幸运的是(从 1.8 开始)使用java.util.Comparator 中的这两种方法真的很容易

    static <T extends Comparable<? super T>> Comparator<T> naturalOrder()
    
    default Comparator<T> thenComparing​(Comparator<? super T> other)
    

    让这些正确的方法成为一个练习。

    【讨论】:

    • 如果排序稳定“对列表进行两次排序与仅使用第二次排序执行相同的操作”是不正确的。
    • @Holger 使用稳定排序,如果您先按名字排序,然后再按姓氏排序,您会得到按“先姓后名”排序的列表 - 这与仅按姓氏排序不同。
    • @JiriTousek 我误读了声明本身。所以在这种形式中,只有当排序条件的所有属性值都不同时才成立。否则,无论排序是否稳定,都是错误的。
    猜你喜欢
    • 1970-01-01
    • 2018-09-10
    • 2017-02-27
    • 1970-01-01
    • 2017-08-11
    • 2013-11-07
    • 1970-01-01
    • 1970-01-01
    • 2013-02-13
    相关资源
    最近更新 更多