问题
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 cannot return the both 2 highest values, as I tried, because it seems to not be possible to remove only one value with the same key, and I also tried to swap them ( making a HashMap was also not the best option). Should I try to use any other kind of collection?
I 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 that the class "Tete" only carries one String and one Integer, the set size is only 3, not 4, as expected. And if I print every numbers, "name3" wont be printed, so I cannot return the 3 biggest values, for example, only "name4", "name2" and "name1" would appear, but "name3" is bigger than "name1"
回答1:
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;
});
}
}
Usage:
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
Remarks:
This particular implementation can return any number of top highest ranks related entries.
Should be also noted that add(...) method takes time proportional to log(n) because TopsCollection backed by TreeMap class.
If needed TopCollection can implement Collection<T> interface to make it work as a real collection.
回答2:
Any Map (including HashMap) can only store one value for any key. Thus, after your three map.put calls, there will be only two elements in your map: [1,"Um"] and [2,"dois2"]. The value "dois" will no longer exist in the map.
If you really need to store multiple values for each key, the way to do this using the Java runtime is to have each key map to a list of values.
HashMap<Integer,ArrayList<String>> map = new HashMap<Integer,ArrayList<String>>();
This does mean that the code to add a value to the map, and to remove a value, is more complicated. To add a value requires code like this:
ArrayList<String> list = map.get(key);
if (list == null) {
list = new ArrayList<String>();
map.put(key, list);
}
list.add(newValue);
Removing a value is similar: you need to get the list, then remove the value from the ArrayList, and remove the key from the map only if the ArrayList's size is now 0.
Alternatives: There are "multi-map" collections in third-party libraries such as Apache Commons (javadoc). Or, as @Keenle suggested, you can use a set where the key is an object containing both the integer and the string. You'd have to write the class for this object, but it would be very simple.
来源:https://stackoverflow.com/questions/27537734/how-to-get-the-two-highest-values-in-a-hashmapinteger-string-making-a-ranking