Search code examples
javahashmaphashtablepriority-queue

Printing hashmap instances ordered using priority queue


I have inserted the distinct words of a txt file and how many times they repeat in a hashmap as keys and values respectively. The thing is, I want to print the k most used words in descending order using a PQ, but although it seems easy to insert the values in the priority queue of integers and then get the k max integers, I can't figure out a way to get the key corresponding to each value back again to print it (the values might not be unique). A solution would be to invert the hashmap, but it doesn't seem as a "safe" choice.

public static void main(int k)throws IOException{

   //Create input stream & scanner
   FileInputStream file = new FileInputStream("readwords.txt");
   Scanner fileInput = new Scanner(file);

   Map<String, Integer> frequency = new HashMap<>();
   LinkedList<String> distinctWords = new LinkedList<String>();
   PriorityQueue<Integer> pQueue = new PriorityQueue<Integer>();

   //Read through file and find the words
   while(fileInput.hasNext()){
       //Get the next word
       String nextWord = fileInput.next().toLowerCase();
       //Determine if the word is in the HashMap
       if(frequency.containsKey(nextWord)) {
           frequency.put(nextWord, frequency.get(nextWord) + 1);
       }
       else {
            frequency.put(nextWord, 1);
            distinctWords.add(nextWord);
       }


    }

    //Close
    fileInput.close();
    file.close();



}

Solution

  • There might be multiple solution, here is mine. create a class with two fields; one for the String and one for the Integer. Make the class implement Comparable and override the method compareTo so it compares the Integers.

    public class WordFrequency implements Comparable<WordFrequency> {
        private String word;
        private Integer frequency;
    
        public WordFrequency(String word, Integer frequency) {
            this.word = word;
            this.frequency = frequency;
        }
    
        // descending order
        @Override
        public int compareTo(WordFrequency o) {
            return o.getFrequency() - this.getFrequency();
        }
    
        public Integer getFrequency() {
            return this.frequency;
        }
    
        @Override
        public String toString() {
            return word + ": " + frequency;
        }
    }
    

    Then, convert your map<String, Integer> to a PriorityQueue<WordFrequency>:

    PriorityQueue<WordFrequency> pQueue = frequency.entrySet().stream()
            .map(m -> new WordFrequency(m.getKey(), m.getValue()))
            .collect(Collectors.toCollection(PriorityQueue::new));
    

    If you want to print it, you must use poll(), otherwise the order is not guaranteed.

    while(!pQueue.isEmpty())
            System.out.println(pQueue.poll());