17

I am trying to take in a List of strings and add them into a Priority Queue with Key and Value. The Key being the word and the value being the string value of the word. Then I need to sort the queue with the highest string value first. The priority queue is not letting me add 2 values.

public static List<String> pQSortStrings(List<String> strings) {
    PriorityQueue<String, Integer> q = new PriorityQueue<>();

    for (int x = 0; x < strings.size(); x++) {
        q.add(strings.get(x),calculateStringValue(strings.get(x)));
    }
    return strings;
}
user3072188
  • 305
  • 1
  • 3
  • 6
  • > "The key being the word and the value being the string of the word" The words are strings? its not clear what you are doing or why you are doing it –  Apr 26 '15 at 01:53
  • You're not using the PQ correctly. See [this](http://stackoverflow.com/q/683041/268093) for a proper example. – MasterAM Apr 26 '15 at 02:33

6 Answers6

26

Problem

PriorityQueue can store a single object in it's each node. So what you are trying to do can not be done as it is.

But you can compose both objects in a single class and then use the PriorityQueue.

You would either need to supply a Comparator or rely on natural ordering by implementing Comparable interface.


Solution

  • Create a class which has String and int as it's members.

    public class Entry {
        private String key;
        private int value;
    
        // Constructors, getters etc.
    }
    
  • Implement Comparable interface and delegate comparison to String.

    public class Entry implements Comparable<Entry> {
        private String key;
        private int value;
    
        public Entry(String key, int value) {
            this.key = key;
            this.value = value;
        }
    
        // getters
    
        @Override
        public int compareTo(Entry other) {
            return this.getKey().compareTo(other.getKey());
        }
    }
    
  • Build the PriorityQueue using this class.

    PriorityQueue<Entry> q = new PriorityQueue<>();
    
  • Add elements as following.

    q.add(new Entry(strings.get(x), calculateStringValue(strings.get(x))));
    

Hope this helps.

Tanmay Patil
  • 6,882
  • 2
  • 25
  • 45
  • Now after Java-8 we could use the Entry class provided by java to do the same operations. That is much more consistent and reliable. – Deepak Yadav Aug 14 '20 at 17:04
21

Using Java-8

PriorityQueue<Map.Entry<String, Integer>> queue = new PriorityQueue<>(Map.Entry.comparingByValue(Comparator.reverseOrder()));

to add a new Entry

queue.offer(new AbstractMap.SimpleEntry<>("A", 10));
Ankit Sharma
  • 1,626
  • 1
  • 14
  • 21
2

Solution

public static List<String> pQSortStrings(List<String> strings) {    
    Queue<String> pq = new PriorityQueue<>((a, b) -> 
        calculateStringValue(b) - calculateStringValue(a));
    for (String str : strings) {
         pq.add(str);
    }
    return strings;
}

Explanation

I believe that the cleanest way to do this is to store Strings in your pq and use a small custom Comparator. In this case, we want to use calculateStringValue and the pq should return highest String values first. Therefore, make a pq of entries and use the following Comparator:

1   Queue<String> pq = new PriorityQueue<>(new Comparator<String>() {
2       @Override
3       public int compare(String a, String b) {
4           return calculateStringValue(b) - calculateStringValue(a);
5       }
6   });
7   for (String str : strings) {
8       pq.add(str);
9   }
10  return strings;

Simpler syntax for the Comparator, replacing lines 1 - 6, is:

Queue<String> pq = new PriorityQueue<>((a, b) -> 
    calculateStringValue(b) - calculateStringValue(a));

If you wanted to return smallest String values first, you could just switch the order around for a and b in the Comparator:

...new PriorityQueue<>((a, b) -> calculateStringValue(a) - calculateStringValue(b));

In general, the pattern a - b sorts by smallest first, and b - a sorts by largest values first.

Paul K.
  • 21
  • 3
1

Many good answers are already present but I am posting this answer because no one has used hashmap in their answers.


You can also make the priority Queue from HashMaps bellow is the example for the same. I am creating a max priority queue. Mind well here I am considering that your hashmap contains only one Entry

PriorityQueue<HashMap<Character, Integer>> pq = new PriorityQueue<>((a, b) -> {
        char keyInA = a.keySet().iterator().next(); // key of a
        char keyInB = b.keySet().iterator().next(); // key of b
        return b.get(keyInB) - a.get(keyInA);
    });

For Insertion of the value in the priority queue.

pq.add(new HashMap<>() {
            {
                put('a', 0);
            }
        });
vishal patel
  • 125
  • 1
  • 7
1

Define a class with a key field and a value field

Class MyClass{
    int key;
    String value
}

Queue<MyClass> queue = new PriorityQueue<>(Comparotor.comparingInt(a -> a.key));
Rohan RM
  • 157
  • 1
  • 2
  • 10
0

Adding to @Tanmay Patil Answer, If you are using Java 8, You can use lambda for more concise code as comparator interface is a functional interface.

public class CustomEntry {
    private String key;
    private int value;

    public CustomEntry(String key, int value) {
        this.key = key;
        this.value = value;
    }

    // getters etc.
}

Now below is the updated code

public static List<String> pQSortStrings(List<String> strings) {
    PriorityQueue<CustomEntry> q = new PriorityQueue<>((x, y) -> {
        // since you want to sort by highest value first
        return Integer.compare(y.getValue(), x.getValue()); 
    });

    for (int x = 0; x < strings.size(); x++) {
        q.add(new CustomEntry(strings.get(x),calculateStringValue(strings.get(x))));
    }
    return strings;
}

To use this priority queue

CustomEntry topEntry = q.peek();
System.out.println("key : " + topEntry.getKey());
System.out.println("value : " + topEntry.getValue());

Same logic can be also be applied by using Map.Entry<String, Integer> provided by java for storing key, pair value

mss
  • 1,423
  • 2
  • 9
  • 18