Kacper Zięba
Kacper Zięba

Reputation: 43

Taking 10 Strings with highest values from hashMap

I want to save all words from titles from a site to a file. Then I want to take 10 most frequent words and save them to the other file. So I've got saving to the file. But I've stucked on looking for those 10 words. My code is only looking for 1 most frequent word and that's it. There're for sure better ways to do that than the one I've done. I'd be really grateful if you show me some tips. I've made through the most popular topics here, but all of them are about looking for the one most frequent word.

List<String> mostRepeatedWords = new ArrayList<>();
Set<Map.Entry<String, Integer>> entrySet = wordsMap.entrySet();
int max = 0;
for (int i = 0; i < entrySet.size(); i++) {
    for (Map.Entry<String, Integer> entry : entrySet) {   //here I'm looking for the word with the highest value in the map
        if (entry.getValue() > max) {
            max = entry.getValue();
            }
     }
     for (Object o : wordsMap.keySet()) {     //here I write this word to a list
         if (wordsMap.get(o).equals(max)) {
             mostRepeatedWords.add(o.toString());
         }
    }
}

@Edit Here's how I've counted the words:

while (currentLine != null) {
    String[] words = currentLine.toLowerCase().split(" ");

    for (String word : words) {
        if (!wordsMap.containsKey(word) && word.length() > 3) {
            wordsMap.put(word, 1);
        } else if (word.length() > 3) {
            int value = wordsMap.get(word);
            value++;
            wordsMap.replace(word, value);
        }
    }
    currentLine = reader.readLine();
}

Upvotes: 0

Views: 125

Answers (3)

WJS
WJS

Reputation: 40062

Does this do it for you?

First, sort the words (i.e. keys) of the map based on the frequency of occurrence in reverse order.

List<String> words = mapOfWords.entrySet().stream()
        .sorted(Entry.comparingByValue(Comparator.reverseOrder()))
        .limit(10)
        .map(Entry::getKey)
        .collect(Collectors.toList());

Then use those keys to print the first 10 words in decreasing frequency.

for (String word : words) {
    System.out.println(word + " " + mapOfWords.get(word));
}

Another more traditional approach not using streams is the following:

Test data

Map<String, Integer> mapOfWords =
        Map.of("A", 10, "B", 3, "C", 8, "D", 9);

Create a list of map entries

List<Entry<String, Integer>> mapEntries =
        new ArrayList<>(mapOfWords.entrySet());

define a Comparator to sort the entries based on the frequency

Comparator<Entry<String, Integer>> comp = new Comparator<>() {
    @Override
    public int compare(Entry<String, Integer> e1,
            Entry<String, Integer> e2) {
            Objects.requireNonNull(e1);
            Objects.requireNonNull(e2);
        // notice e2 and e1 order is reversed to sort in descending order.
        return Integer.compare(e2.getValue(), e1.getValue());
    }
};

The above does the equivalent of the following which is defined in the Map.Entry class

Comparator<Entry<String,Integer>> comp =
   Entry.comparingByValue(Comparator.reverseOrder());

Now sort the list with either comparator.

mapEntries.sort(comp);

Now just print the list of entries. If there are more than 10 you will need to put in a limiting counter or use a mapEntries.subList(0, 10) as the target of the for loop.

for (Entry<?,?> e : mapEntries) {
     System.out.println(e);
}

Upvotes: 3

Eritrean
Eritrean

Reputation: 16498

Assuming you have already your frequency map which might look something like:

Map<String,Integer> wordsMap = Map.of( "foo", 2,
                                       "bar", 7,
                                       "baz", 5,
                                       "doo", 9,
                                       "tot", 2,
                                       "gee", 12);

You could create another map, i.e a top ten map (in my demo below top three), by sorting your map by value in reverse order and limit it to the first ten entries

Map<String,Integer> topThree = wordsMap.entrySet()
                                       .stream()
                                       .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
                                       .limit(3)
                                       .collect(Collectors.toMap(
                                          Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,LinkedHashMap::new));

System.out.println(topThree);

//{gee=12, doo=9, bar=7}

Upvotes: 0

janik
janik

Reputation: 11

You could save the most frequent word to an array and check if the next word you found already exists in that array. Then you search for the next most frequent word that does not exist in that array.

Upvotes: 0

Related Questions