使用比较器按预定义的优先顺序排序

Sort by predefined priority order using comparator

我有以下问题需要解决。我正在使用 Java.

餐厅识别 3 种类型的顾客:“NEWBIES”、“REGULARS”和“VIPs”。当客户下订单时,所有订单都加入队列。然而,订单始终以 VIP 服务于常客之前服务的方式提供,常客服务于新手之前。

我需要一个 class 可以用来对客户订单进行排序。如果两个客户属于同一类型,则应使用orderID对其进行排序。

如何使用比较器根据客户类型按订单优先级排序?

假设我已经有以下class订单

public class Order
{
    public static int orderID;
    private int tableNumber;
    private String[] orderDetails;
    private String customerType;

    public Order(int tableNumber, String[] orderDetails, String customerType)
    {
        this.tableNumber = tableNumber;
        this.orderDetails = orderDetails;
        this.customerType = customerType;
        orderID += 1;
    }
    // get and set methods declared
}

我已经实现了比较器如下:

import java.util.Comparator;

public class OrderComparator implements Comparator<Order>
{
    @Override
    public int compare(Order o1, Order o2)
    {
        if(o1.getType().equals(o2.getType()))
            return o1.getOrderID - o2.getOrderID;
        else
        // How does comparing the customer type text ensure that 
        // it will be printed in the right order?
            return o1.getType().compareTo(o2.getType());
    }
}

你可以阅读这个问题How to sort a collection by multiple fields。特别是第二个答案,列出第一个选项。

您不仅想要 sort on multiple fields,还想要使用其中一个字段进行自定义排序。

在下面的代码中,我填写了 class Order 和 class OrderComparator 的缺失部分。代码后的注释。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Order {
    public static final String  NEWBIES = "NEWBIES";
    public static final String  REGULARS = "REGULARS";
    public static final String  VIP = "VIP";

    private static int  orderId;

    private int orderID;
    private int tableNumber;
    private String[] orderDetails;
    private String customerType;

    public Order(int tableNumber, String[] orderDetails, String customerType) {
        this.tableNumber = tableNumber;
        this.orderDetails = orderDetails;
        this.customerType = customerType;
        orderID = ++orderId;
    }

    public int getOrderID() {
        return orderID;
    }

    public int getTableNumber() {
        return tableNumber;
    }

    public String[] getOrderDetails() {
        return orderDetails;
    }

    public String getType() {
        return customerType;
    }

    public String toString() {
        return String.format("%d %s", orderID, customerType);
    }

    public static void main(String[] args) {
        Order order1 = new Order(0, null, VIP);
        Order order2 = new Order(0, null, REGULARS);
        Order order3 = new Order(0, null, REGULARS);
        List<Order> list = new ArrayList<>();
        list.add(order3);
        list.add(order2);
        list.add(order1);
        System.out.println("Unordered: " + list);
        Collections.sort(list, new OrderComparator());
        System.out.println("Ordered: " + list);
    }
}

class OrderComparator implements Comparator<Order> {

    @Override
    public int compare(Order o1, Order o2) {
        if (o1.getType().equals(o2.getType())) {
            return o1.getOrderID() - o2.getOrderID();
        }
        else {
            if (Order.VIP.equals(o1.getType())) {
                return -1;
            }
            else if (Order.VIP.equals(o2.getType())) {
                return 1;
            }
            else if (Order.REGULARS.equals(o1.getType())) {
                return -1;
            }
            else if (Order.REGULARS.equals(o2.getType())) {
                return 1;
            }
            else if (Order.NEWBIES.equals(o1.getType())) {
                return -1;
            }
            else if (Order.NEWBIES.equals(o2.getType())) {
                return 1;
            }
            throw new RuntimeException("Unexpected customer type.");
        }
    }
}
  • 我将方法 main 添加到 class Order 以测试代码。
  • 我将方法 toString 添加到 class Order 以便能够检查代码是否产生了预期的结果。
  • 我知道您想要一种用于 Order 对象的分子。因此,我将成员 orderID 设为实例成员,因为每个 Order 都有自己的 ID,并且我添加了一个新的静态成员 orderId (请注意 Java 区分大小写),这会产生一个每个新 Order 对象的新的唯一订单 ID。
  • 您希望 VIP 订单在 REGULARS 订单之前出现,并且您希望 REGULARS 订单在 NEWBIES 订单之前出现。默认情况下,Comparator 按升序排序,因此您希望 VIP 最低,NEWBIES 最高(纯粹为了排序目的)。所以在方法 compare(属于 class OrderComparator)中,如果 o1 的类型是 VIP 而 o2 的类型是 REGULARS 那么你希望 VIP 低于 REGULAR。因此在那种情况下,方法 compare returns -1(减一).

运行 上面的代码产生以下输出。

Unordered: [3 REGULARS, 2 REGULARS, 1 VIP]
Ordered: [1 VIP, 2 REGULARS, 3 REGULARS]

请注意,由于 customerType(在 class Order 中)是一个 String,因此有可能创建一个 Order 对象无效的 customerType 值。您可以更改 class Order 的构造函数并添加对提供的值(对于 customerType)的检查,如果提供的值无效则抛出 Exception。或者您可以使用 enum (also known as enumerated types)。下面的代码使用 enum 而不是 String 作为 customerType - 这也简化了方法 compare in class OrderComparator.

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Order {
    private static int  orderId;

    private int orderID;
    private int tableNumber;
    private String[] orderDetails;
    private CustomerType customerType;

    public Order(int tableNumber, String[] orderDetails, CustomerType customerType) {
        this.tableNumber = tableNumber;
        this.orderDetails = orderDetails;
        this.customerType = customerType;
        orderID = ++orderId;
    }

    public int getOrderID() {
        return orderID;
    }

    public int getTableNumber() {
        return tableNumber;
    }

    public String[] getOrderDetails() {
        return orderDetails;
    }

    public CustomerType getType() {
        return customerType;
    }

    public String toString() {
        return String.format("%d %s", orderID, customerType);
    }

    public static void main(String[] args) {
        Order order1 = new Order(0, null, CustomerType.VIP);
        Order order2 = new Order(0, null, CustomerType.REGULARS);
        Order order3 = new Order(0, null, CustomerType.REGULARS);
        List<Order> list = new ArrayList<>();
        list.add(order3);
        list.add(order2);
        list.add(order1);
        System.out.println("Unordered: " + list);
        Collections.sort(list, new OrderComparator());
        System.out.println("Ordered: " + list);
    }
}

class OrderComparator implements Comparator<Order> {

    @Override
    public int compare(Order o1, Order o2) {
        if (o1.getType().equals(o2.getType())) {
            return o1.getOrderID() - o2.getOrderID();
        }
        else {
            return o2.getType().ordinal() - o1.getType().ordinal();
        }
    }
}

enum CustomerType {
    NEWBIES, REGULARS, VIP
}