-1

I have the following problem to solve. I am using Java.

A restaurant recognizes 3 types of customers: “NEWBIES”, “REGULARS” and “VIPs”. When customers place their orders, all the orders join a queue. However the orders are always served in such a way that VIPs are served before regulars who are served before newbies.

I need a class which could be used to sort the customer orders. In case two customers are of the same type, the orderID should be used to sort them.

How can I sort by order priority based on the customer type using comparator?

Assuming I already have the following class 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
}

I have implemented the comparator as follows:

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());
    }
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
adhu
  • 35
  • 6

2 Answers2

0

You can read this question How to sort a collection by multiple fields. Especially the second answer, first option listed.

Gnut
  • 541
  • 1
  • 5
  • 19
  • But for example if i do the following: return o1.getType().compareTo(o2.getType()). How does this ensure that the VIP will be output before Regulars and newbies simply based on text comparison. – adhu Jul 04 '21 at 05:40
  • For cases like this (you have a finite collection of constants), you should use an Enum to represent your 3 types of guest. The default comparator for string is indeed inappropriate. For enums, its natural ordering is the order of declaration, so you just have to declare the types in order of importance. – Gnut Jul 04 '21 at 05:46
0

Not only do you want to sort on multiple fields, you also want a custom sort with one of those fields.

In the code below, I filled in the missing parts of both class Order and class OrderComparator. Notes after the code.

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.");
        }
    }
}
  • I added method main to class Order in order to test the code.
  • I added method toString to class Order so as to be able to check whether the code produces the expected results.
  • I understand that you want a kind of numerator for Order objects. Hence I made member orderID an instance member since every Order has its own ID and I added a new static member orderId (note that Java is case sensitive) which produces a new, unique order ID for each new Order object.
  • You want VIP orders to come before REGULARS orders and you want REGULARS orders to come before NEWBIES orders. By default, a Comparator sorts by ascending order, hence you want VIP to be lowest and NEWBIES to be highest (purely for sorting purposes). So in method compare (of class OrderComparator), if, for example, the type of o1 is VIP and the type of o2 is REGULARS then you want VIP to be lower that REGULAR. Hence in that situation, method compare returns -1 (minus one).

Running the above code produces the following output.

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

Note that since customerType (in class Order) is a String, there is a chance that an Order object will be created with an invalid customerType value. You could change the constructor of class Order and add a check for the supplied value (for customerType) and throw an Exception if the supplied value is invalid. Or you could use enum (also known as enumerated types). The below code uses enum instead of String for customerType - which also simplifies method 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
}
Abra
  • 19,142
  • 7
  • 29
  • 41