Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java PriorityQueue custom Comparator

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.

like image 720
Vladimir S. Avatar asked May 07 '17 16:05

Vladimir S.


People also ask

How does PriorityQueue use Comparator?

PriorityQueue. comparator() method shares an important function of setting and returning the comparator that can be used to order the elements in a PriorityQueue. The method returns a null value if the queue follows the natural ordering pattern of the elements.

Is PriorityQueue thread safe in Java?

Since PriorityQueue is not thread-safe, java provides PriorityBlockingQueue class that implements the BlockingQueue interface to use in a java multithreading environment. The queue retrieval operations poll, remove, peek, and element access the element at the head of the queue.

What is PriorityQueue in Java?

A priority queue in Java is a special type of queue wherein all the elements are ordered as per their natural ordering or based on a custom Comparator supplied at the time of creation.


1 Answers

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 );
}
like image 167
Mike Nakis Avatar answered Sep 25 '22 00:09

Mike Nakis