4

I have a priority queue that contains Patients which look like this:

patientQueue.add(new Patient(idNr, name, emergencyNr));

Now I want to sort the Queue first by emergencyNr and then idNr. The `name´ doesn´t matter.

Right now I can sort the priority queue with comparable implemented in patient:

    @Override
    public int compareTo(Patient otherRequest) {
        return Integer.compare(isEmergencyCase(), otherRequest.isEmergencyCase());
    }

How can I implement an method that also sorts by IdNr? So if all EmergencyNr is equals then the lowest idNr will be first.

Thanks in advance guys!

PakkuDon
  • 1,627
  • 4
  • 22
  • 21
Johan
  • 53
  • 1
  • 6

2 Answers2

4

Just add another condition in compareTo():

@Override
public int compareTo(Patient otherRequest) {
    int r = Integer.compare(emergencyNr, otherRequest.emergencyNr);
    return r == 0 ? Integer.compare(idNr, otherRequest.idNr) : r;
}

or use constructor that accepts Comparator, like:

Queue<Patient> q 
    = new PriorityQueue<>(CAPACITY, Comparator.comparing(Patient::getEmegencyNr)
                                              .thenComparing(Patient::getIdNr));

P. S. To check correctness, use poll() instead of directly printing queue contents:

Patient p;
while((p = q.poll()) != null) 
    System.out.println(p);
Alex Salauyou
  • 14,185
  • 5
  • 45
  • 67
  • Thanks, i tried that before but t dosent work when you have long queues. There are small bugs when i prinst ´patientQueue´ Ive got this: – Johan Aug 20 '15 at 13:56
  • ` Patient: [ID=2, Name=1, emergencyNr=1] , Patient: [ID=16, Name=10, emergencyNr=10] , Patient: [ID=4, Name=1, emergencyNr=1] , Patient: [ID=7, Name=1, emergencyNr=1] , Patient: [ID=8, Name=1, emergencyNr=1] , Patient: [ID=17, Name=10, emergencyNr=10] , Patient: [ID=10, Name=1, emergencyNr=1] , Patient: [ID=11, Name=1, emergencyNr=1] , Patient: [ID=12, Name=0, emergencyNr=0] , Patient: [ID=13, Name=0, emergencyNr=0] , Patient: [ID=14, Name=0, emergencyNr=0] , Patient: [ID=6, Name=0, emergencyNr=0] , Patient: [ID=9, Name=1, emergencyNr=1] , Patient: [ID=1, Name=1, emergencyNr=1]` – Johan Aug 20 '15 at 13:57
  • If i just have 3 or 4 patients it works... maybe just luck? – Johan Aug 20 '15 at 13:59
  • @Johan `PriorityQueue` iterator doesn't return elements in priority order: http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#iterator%28%29, that's why you receive random result when printing. – Alex Salauyou Aug 20 '15 at 14:04
  • Ok thanks, but i dont want to empty the queue when i print it. I still need to have the queue with same content, so that i can add new patients after i have printed the queue. The only time i want to empty the queue is when all patients are finished. @SashaSalauyou – Johan Aug 20 '15 at 14:31
  • If you need to output objects in particular order every time without removing them from collection, use `TreeSet` or some other `SortedSet` instead of queue. `PriorityQueue` doesn't provide such facility. – Alex Salauyou Aug 20 '15 at 14:35
  • So is it not possible to copy the current priorityQueue before ".poll" and then copy the queue back? @SashaSalauyou – Johan Aug 20 '15 at 15:03
  • @Johan you can do it explicitly, but I'd better implement own collection which is relevant to use-case. – Alex Salauyou Aug 20 '15 at 15:55
  • I got it! And it works with TreeSet :) Now my problem is how to change the emergencyNr into a Patient. I can change it with following code but the sortning doesnt updates after i change emergencyNr. Have any idea? @SashaSalauyou – Johan Aug 20 '15 at 17:37
  • System.out.println("Which patient do u want to change?"); Scanner scan = new Scanner(System.in); String name = scan.nextLine(); Iterator iterator = patientQueue.iterator(); while (iterator.hasNext()) { if (iterator.next().getName().equals(name) == true) { System.out.println("Enter new emergencyNr? "); int emergencyNr1 = scan.nextInt(); iterator.next().setEmergencyCase(emergencyNr1); } } – Johan Aug 20 '15 at 17:38
  • Take an entity out of set by `Set#remove()`, then change value, than add it back to set. – Alex Salauyou Aug 20 '15 at 18:08
  • Objects take their places in collection on addition, and when you mutate their key properties while they locate in collection, it doesn't affect their location, but can even break inner structure of entire collection. – Alex Salauyou Aug 20 '15 at 18:12
  • Is it this lines you mean to remove the iterated Patient? Iterator iterator = patientQueue.iterator(); while (iterator.hasNext()) { if (iterator.next().getName().equals(name) == true) { patientQueue.remove(iterator.next());@SashaSalauyou – Johan Aug 20 '15 at 18:31
  • @Johan I'm not sure that TreeSet iterator supports `remove()`... but you can try. I would suggest to write a simple decorator for TreeSet, that has its own iterator and rearranges entries when key property of some entry is modified through setter. Because your use-case is not typical for standard TreeSet, it requires non-typical implementation – Alex Salauyou Aug 21 '15 at 05:07
0

Hava a look at https://stackoverflow.com/a/683049/197574

There the constructor public PriorityQueue(int initialCapacity, Comparator comparator) is used.

Your Coparator should contain something like this

if (this.emergency != other.emergency)
    return other.emergency - this.emergency
else
    return other.id - this.id
DerMike
  • 15,594
  • 13
  • 50
  • 63