Java PriorityQueue custom Comparator

Vladimir S. :

In my PriorityQueue I have 2 types of customers, VIP and regular. I want to serve VIP first, then regular.

If CustomerID < 100 it is considered to be VIP.

If a customer is VIP he goes at the end of VIP part of the queue

If a customer is regular he goes at the end of the entire queue.

In other words, I want to sort by boolean VIP value, while preserving the order in which customers came in.

Here's my Order class

public class Order implements Comparable<Order> {
    private final int customerID;
    private final int amount;
    private final boolean vip_status;

    public Order(int customerID, int amount) { 
        this.customerID = customerID;
        this.amount = amount;
        this.vip_status = customerID < 100 ? true : false;

    }

    @Override
    public int compareTo(Order o) {
        if (vip_status && !o.vip_status) {
            return -1;
        }
        if (!vip_status && o.vip_status)
            return 1;
        return 0;
    }

    public int getCustomerID() {
        return customerID;
    }

    public int getAmount() {
        return amount;
    }

    public boolean isVip_status() {
        return vip_status;
    }
}

Here's my attempt to fill the queue:

import java.util.PriorityQueue;

public class MyPriorityQueue {
    public static void main(String[] args) {
        PriorityQueue<Order> queue = new PriorityQueue<>();
        Order o1 = new Order(1, 50);
        Order o2 = new Order(5, 30);
        Order o3 = new Order(4, 10);
        Order o4 = new Order(150, 5);
        Order o5 = new Order(2, 5);
        Order o6 = new Order(200, 5);

        queue.add(o1);
        queue.add(o2);
        queue.add(o3);
        queue.add(o4);
        queue.add(o5);
        queue.add(o6);

        while(!queue.isEmpty()){
            Order s = queue.poll();
            System.out.printf("VIP Status: %s CustomerID: %s Amount: %s%n", 
                        s.isVip_status(), s.getCustomerID(), s.getAmount());
        }
    }
}

RESULT that I'm getting (which is wrong):

VIP Status: true CustomerID: 1 Amount: 50
VIP Status: true CustomerID: 5 Amount: 30
VIP Status: true CustomerID: 2 Amount: 5
VIP Status: true CustomerID: 4 Amount: 10
VIP Status: false CustomerID: 150 Amount: 5
VIP Status: false CustomerID: 200 Amount: 5

This is what I expected to see (CustomerID 2 and 4 should be in the same order they came in):

VIP Status: true CustomerID: 1 Amount: 50
VIP Status: true CustomerID: 5 Amount: 30
VIP Status: true CustomerID: 4 Amount: 10
VIP Status: true CustomerID: 2 Amount: 5
VIP Status: false CustomerID: 150 Amount: 5
VIP Status: false CustomerID: 200 Amount: 5

UPDATE: I don't want sort by any other column except VIP. I don't want add "date" because it feels like a hack, rather than understanding how Java works.

Mike Nakis :

It appears that the PriorityQueue class that java comes with out of the box feels free to reorder items if they compare as equal to each other.

(This is not "how java works", it is just a little perversion on behalf of a certain class that comes with the Java Runtime.)

So, here is something that will probably work:

  1. Introduce a new OrderPlacement class, containing a) an Order and b) an int priority.

  2. In your PriorityQueue add OrderPlacement objects instead of Order objects.

  3. When you create a new OrderPlacement object, issue a new priority for it, by incrementing a counter.

Then, your OrderPlacement object can have a compareTo() method that looks like this:

@Override
public int compareTo( OrderPlacement o ) 
{
    int d = -Boolean.compare( order.vip_status, o.order.vip_status );
    if( d != 0 )
        return d;
    return Integer.compare( priority, o.priority );
}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=445510&siteId=1