Home > database >  How to return key associated to highest value in nested map (Java)?
How to return key associated to highest value in nested map (Java)?

Time:06-08

I am trying to build a simple program that in essence will return the key associated to the highest value in a nested Map. For example (below numbers are just an example, they are not real).

public class MultiValueMap {

    public static void main(String[] args) {

        Map<String, HashMap<String, Integer>> singers = new HashMap<>();
        singers.put("Elvis", new HashMap<>());
        singers.get("Elvis").put("All Shook up", 8);
        singers.get("Elvis").put("Don't be Cruel", 5);
        singers.get("Elvis").put("Viva las Vegas", 3);

    }

}

The idea here is to get either the top song or lowest rated song. The program should return for example "All Shook Up" if I want the top rated song.

Any ideas on how to accomplish this?

CodePudding user response:

Note that, given you want min and max a HashMap is not the most suitable structure.
You'll need to traverse over all values every time you want an answer to this question. If you use a TreeSet you can reduce that to a simple binary search on all keys.

record SongScore(String songName, int score)  {}

....

Map<String, TreeSet<SongScore>> singers = new HashMap<>();
TreeSet<SongScore> songs = new TreeSet<>(Comparator.comparingInt(SongScore::score));
songs.add(new SongScore("All Shook up", 8));
songs.add(new SongScore("Don't be Cruel", 5));
songs.add(new SongScore("Viva las Vegas", 3));
singers.put("Elvis", songs);

var lowest = singers.values().stream().map(TreeSet::first).min(Comparator.comparingInt(SongScore::score));
var highest = singers.values().stream().map(TreeSet::last).max(Comparator.comparingInt(SongScore::score));

CodePudding user response:

Given

Given your map with

singer_map: interpret -> title_map
title_map: title -> rating

like:

Map<String, HashMap<String, Integer>> singers = new HashMap<>();
singers.put("Elvis", new HashMap<>());
singers.get("Elvis").put("All Shook up", 8);
singers.get("Elvis").put("Don't be Cruel", 5);
singers.get("Elvis").put("Viva las Vegas", 3);

Algorithm

Now define a temporary entry variable for the favoriteTitle. Take the title-map like Map<String, Integer> titles = singers.get("Elvis") and iterate over each entry (e.g. a for-each loop).

In the loop-body of each iteration: If an entry is higher then favoriteTitle or favoriteTitle is empty, then store the current entry.

After the loop you have the favoriteTitle with highest rating for this singer. If the singer has no titles, then there is also no favorite.

What if all or the more than 1 highest rated titles have the same rating?

Sample code

Map<String, Integer> titles = singers.get("Elvis");
Map.Entry<String, Integer> favoriteTitle;

for (Map.Entry<String, Integer> t : titles) {
  System.out.println(t.getKey()   " rated "   t.getValue());
  if (favoriteTitle == null || favoriteTitle.getValue() < t.getValue()) {
    favoriteTitle = t;
  }
}
System.out.println("Favorite: "   favoriteTitle.getKey()   " rated "   favoriteTitle.getValue());

See also:

CodePudding user response:

In Java 8 use a stream with Comparator like in Finding Key associated with max Value in a Java Map.

CodePudding user response:

Using Java8 streams you can use a pretty simple one liner. This example assumes there is at least one entry in the map with a non-null value.

map.entrySet()  // get all entries
   .stream()   // stream over them
   .max(Comparator.comparingInt(Map.Entry::getValue))  // max over all entries by value (here: rating), comparing them as integers 
   .get().getKey()  // get the entry, then the key (here: title)

 
  •  Tags:  
  • java
  • Related