How to get the two highest values in a HashMap <Integer, String> while doing a rating
I have the following code:
public class Tester {
public static void main(String[] args) {
HashMap<Integer,String> map = new HashMap<Integer,String>();
map.put(1, "one");
map.put(2, "twp");
map.put(2, "two2");
int highest = Integer.MIN_VALUE;
String highestString = null;
int secondHighest = Integer.MIN_VALUE;
String secondHighestString = null;
if (highest == Integer.MIN_VALUE){
highest = Collections.max(map.keySet() );
highestString = map.get(highest);
map.remove(highest);
}
if (secondHighest == Integer.MIN_VALUE ){
secondHighest = Collections.max(map.keySet() );
secondHighestString = map.get(secondHighest);
map.remove(secondHighest);
}
System.out.println(highest + highestString);
System.out.println(secondHighest + secondHighestString);
}
}
I can't get both of the highest values back as I tried, because it seems impossible to delete only one value with the same key, and I also tried swapping them (making HashMap not the best option either). Should I try to use any other collection?
I've also tried:
TreeSet<Tete> set = new TreeSet<Tete>();
set.add(new Tete("name1", 1));
set.add(new Tete("name2",4));
set.add(new Tete("name3",4));
set.add(new Tete("name4",12));
System.out.println(set.size());
Assuming the "Tete" class contains only one string and one integer, the size of the set is only 3, not 4 as expected. And if I print all the numbers, "name3" is not printed, so I cannot return the 3 largest values, for example, only "name4", "name2" and "name1" will appear, but "name3" is greater than "name1" "
source to share
To solve the ranking problem, I would write a custom class something like this:
public class TopsCollection<D> {
private final TreeMap<Integer, List<D>> map
= new TreeMap<>((lhv, rhv) -> rhv.compareTo(lhv));
public TopsCollection() {}
public void add(Integer score, D name) {
List<D> vals = map.get(score);
if (vals == null) {
vals = new ArrayList<>();
map.put(score, vals);
}
vals.add(name);
}
public List<D> getTops(int n) {
return map.
values().
stream().
limit(n).
reduce(new ArrayList<D>(), (lhv, rhv) -> {
lhv.addAll(rhv);
return lhv;
});
}
}
Using:
TopsCollection<String> tc = new TopsCollection<>();
tc.add(12, "nome4");
tc.add(1, "nome1");
tc.add(4, "nome3");
tc.add(4, "nome2");
List<String> tops = tc.getTops(2); // contains 3 elements: nome4, nome3, nome2
Notes:
This particular implementation can return any number of highest ranked records.
It should also be noted that the method add(...)
takes proportional time log(n)
because TopsCollection is supported by the class TreeMap
.
TopCollection
Can optionally implement an interface Collection<T>
to act like a real collection.
source to share
Anyone Map
(including HashMap
) can only store one value for any key. Thus, after three calls map.put
, your map will only have two elements: [1,"Um"]
and [2,"dois2"]
. The value "dois"
will no longer appear on the map.
If you really need to store multiple values for each key, the way to do it with the Java runtime is to map each keymap to a list of values.
HashMap<Integer,ArrayList<String>> map = new HashMap<Integer,ArrayList<String>>();
This means that the code for adding a value to a map and for removing a value is more complex. Adding a value requires the following code:
ArrayList<String> list = map.get(key);
if (list == null) {
list = new ArrayList<String>();
map.put(key, list);
}
list.add(newValue);
Deleting a value is similar: you need to get the list, then remove the value from ArrayList
and remove the key from the map, only if the size is ArrayList
now 0.
Alternatives: There are multi-map collections in third party libraries like Apache Commons ( javadoc ). Or, as @Keenle suggested, you can use a set where the key is an object containing both an integer and a string. You will have to write a class for this object, but that would be very simple.
source to share