Asked  7 Months ago    Answers:  5   Viewed   25 times

How do I get a PriorityQueue to sort on what I want it to sort on?

Also, is there a difference between the offer and add methods?

 Answers

41

Use the constructor overload which takes a Comparator<? super E> comparator and pass in a comparator which compares in the appropriate way for your sort order. If you give an example of how you want to sort, we can provide some sample code to implement the comparator if you're not sure. (It's pretty straightforward though.)

As has been said elsewhere: offer and add are just different interface method implementations. In the JDK source I've got, add calls offer. Although add and offer have potentially different behaviour in general due to the ability for offer to indicate that the value can't be added due to size limitations, this difference is irrelevant in PriorityQueue which is unbounded.

Here's an example of a priority queue sorting by string length:

// Test.java
import java.util.Comparator;
import java.util.PriorityQueue;

public class Test {
    public static void main(String[] args) {
        Comparator<String> comparator = new StringLengthComparator();
        PriorityQueue<String> queue = new PriorityQueue<String>(10, comparator);
        queue.add("short");
        queue.add("very long indeed");
        queue.add("medium");
        while (queue.size() != 0) {
            System.out.println(queue.remove());
        }
    }
}

// StringLengthComparator.java
import java.util.Comparator;

public class StringLengthComparator implements Comparator<String> {
    @Override
    public int compare(String x, String y) {
        // Assume neither string is null. Real code should
        // probably be more robust
        // You could also just return x.length() - y.length(),
        // which would be more efficient.
        if (x.length() < y.length()) {
            return -1;
        }
        if (x.length() > y.length()) {
            return 1;
        }
        return 0;
    }
}

Here is the output:

short

medium

very long indeed

Tuesday, June 1, 2021
 
mgraph
answered 7 Months ago
66

The scanner can also use delimiters other than whitespace.

Easy example from Scanner API:

 String input = "1 fish 2 fish red fish blue fish";

 // \s* means 0 or more repetitions of any whitespace character 
 // fish is the pattern to find
 Scanner s = new Scanner(input).useDelimiter("\s*fish\s*");

 System.out.println(s.nextInt());   // prints: 1
 System.out.println(s.nextInt());   // prints: 2
 System.out.println(s.next());      // prints: red
 System.out.println(s.next());      // prints: blue

 // don't forget to close the scanner!!
 s.close(); 

The point is to understand the regular expressions (regex) inside the Scanner::useDelimiter. Find an useDelimiter tutorial here.


To start with regular expressions here you can find a nice tutorial.

Notes

abc…    Letters
123…    Digits
d      Any Digit
D      Any Non-digit character
.       Any Character
.      Period
[abc]   Only a, b, or c
[^abc]  Not a, b, nor c
[a-z]   Characters a to z
[0-9]   Numbers 0 to 9
w      Any Alphanumeric character
W      Any Non-alphanumeric character
{m}     m Repetitions
{m,n}   m to n Repetitions
*       Zero or more repetitions
+       One or more repetitions
?       Optional character
s      Any Whitespace
S      Any Non-whitespace character
^…$     Starts and ends
(…)     Capture Group
(a(bc)) Capture Sub-group
(.*)    Capture all
(ab|cd) Matches ab or cd
Tuesday, June 1, 2021
 
subroutines
answered 7 Months ago
44

A LinkedList is the worst choice. Either use an ArrayList (or, more generally, a RandomAccess implementor), or PriorityQueue. If you do use a list, sort it only before iterating over its contents, not after every insert.

One thing to note is that the PriorityQueue iterator does not provide the elements in order; you'll actually have to remove the elements (empty the queue) to iterate over its elements in order.

Friday, July 30, 2021
 
123r789
answered 4 Months ago
20

If you need to have an ordering according the insertion order you need to use an extra element for timestamp. I.e. on insertions and equal weight use timestamp to see which element was inserted first. So CustomObject should be something like:

class CustomObject {  
   int weight;  
   long timestamp;  
}

And the comparison should be:

public int compareTo (CustomObject o) {  
    int thisWeight = this.weight;  
    int thatWeight = o.weight;  
    if (thisWeight != thatWeight) {  
        return thisWeight - thatWeight;  
    }  
    else {  
        return this.timestamp - o.timestamp;  
    }  
}  

The smaller timestamp means it was inserted earlier so you keep in the insertion order.

You could also use a "logical" time by maintaining a counter that you update on each add or remove.

Tuesday, August 3, 2021
 
qwertylpc
answered 4 Months ago
100

In case anyone is wondering, the Register is correct, my photo user control tag was just not formed properly. I did have it as:

<ssctrl:photo ID="Photo" Key="<%# Eval("PageTemplatePK") %>" runat="server" />

and the Key property needed to use single quotes instead of double quotes because it was using an Eval expression:

<ssctrl:photo ID="Photo" Key='<%# Eval("PageTemplatePK") %>' runat="server" />

After that, it worked.

Saturday, November 6, 2021
 
Awais Qarni
answered 4 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share