简体   繁体   English

如何在HashMap中获取两个最高值 <Integer,String> ,排名

[英]How to get the two highest values in a HashMap<Integer,String>, making a ranking

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). 我尝试不能返回两个最高值,因为似乎不可能只删除一个具有相同键的值,我也尝试交换它们(使HashMap也不是最佳选择)。 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. 假设类“Tete”只携带一个String和一个Integer,则设置大小仅为3,而不是4,如预期的那样。 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" 如果我打印每个数字,“name3”将不会打印,所以我不能返回3个最大值,例如,只会出现“name4”,“name2”和“name1”,但“name3”大于“name1” “

Any Map (including HashMap ) can only store one value for any key. 任何Map (包括HashMap )只能为任何键存储一个值。 Thus, after your three map.put calls, there will be only two elements in your map: [1,"Um"] and [2,"dois2"] . 因此,在三次map.put调用之后,地图中只有两个元素: [1,"Um"][2,"dois2"] The value "dois" will no longer exist in the map. 地图中将不再存在值"dois"

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. 如果确实需要为每个键存储多个值,那么使用Java运行时执行此操作的方法是将每个键映射到值列表。

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. 删除值类似:您需要获取列表,然后从ArrayList删除值,并仅在ArrayList的大小为0时从映射中删除键。

Alternatives: There are "multi-map" collections in third-party libraries such as Apache Commons ( javadoc ). 替代方案:第三方库中有“多地图”集合,例如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. 或者,如@Keenle建议,您可以使用一组,其中的关键是同时包含整数和字符串的对象。 You'd have to write the class for this object, but it would be very simple. 你必须为这个对象编写类,但它会非常简单。

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. 还应注意add(...)方法需要时间与log(n)成比例,因为TopsCollection由TreeMap类支持。

If needed TopCollection can implement Collection<T> interface to make it work as a real collection. 如果需要TopCollection可以实现Collection<T>接口,使其作为真正的集合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM