【问题标题】:Sort by predefined priority order using comparator使用比较器按预定义的优先级顺序排序
【发布时间】:2021-07-04 05:00:50
【问题描述】:

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

一家餐厅可以识别 3 类顾客:“NEWBIES”、“REGULARS”和“VIP”。当客户下订单时,所有订单都会加入队列。然而,订单总是以这样的方式提供,即 VIP 在常客之前服务,而在新手之前服务。

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

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

假设我已经有以下类 Order

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

【问题讨论】:

  • StackOverflow 不是代码编写服务。见How to Ask
  • 到目前为止你尝试了什么?
  • 我更新了@NomadMaker 的问题。我试过实现比较器。

标签: java comparator


【解决方案1】:

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

在下面的代码中,我填写了Order 类和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 添加到类Order 以测试代码。
  • 我在Order类中添加了方法toString,以便能够检查代码是否产生了预期的结果。
  • 我知道您想要Order 对象的一种分子。因此,我将成员 orderID 设为实例成员,因为每个 Order 都有自己的 ID,并且我添加了一个新的静态成员 orderId(注意 Java 区分大小写),它为每个新的 @987654335 生成一个新的、唯一的订单 ID @对象。
  • 您希望 VIP 订单出现在 REGULARS 订单之前,并且您希望 REGULARS 订单出现在 NEWBIES 订单之前。默认情况下,Comparator 按升序排序,因此您希望 VIP 最低,NEWBIES 最高(纯粹出于排序目的)。因此,在方法@​​987654337@(属于OrderComparator 类)中,例如,如果o1 的类型是VIP,o2 的类型是REGULARS,那么您希望VIP 低于REGULAR。因此,在这种情况下,方法 compare 返回 -1(减一)。

运行上述代码会产生以下输出。

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

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

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
}

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 但例如,如果我执行以下操作:返回 o1.getType().compareTo(o2.getType())。这如何确保仅基于文本比较,VIP将在Regulars和newbies之前输出。
    • 对于这样的情况(你有一个有限的常量集合),你应该使用一个 Enum 来表示你的 3 种访客类型。字符串的默认比较器确实不合适。对于枚举,它的自然顺序是声明的顺序,所以你只需要按照重要性顺序声明类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多