在HashMap中获取前N个键(按值排序)的最佳方法

时间:2013-09-24 02:05:10

标签: java

原始数据如下所示:

String data = "{ \"a\":1, \"b\":3 , \"c\":-1 }";

我的第一步是将其转换为HashMap:

Gson gson = new Gson();
HashMap<String, Double> map = gson.fromJson(data, HashMap.class);

然后按键值对键进行排序:

public static List<String> sortHashMap(final HashMap<String, Double> map) {
    Set<String> set = map.keySet();
    List<String> keys = new ArrayList<String>(set);

    Collections.sort(keys, new Comparator<String>() {

        @Override
        public int compare(String s1, String s2) {
            if (map.get(s1) < map.get(s2)) {
                return 1;
            }
            return 0;
        }
    });

    return keys;
}

最后,获得前N个键:

keys.subList(0, N);

我终于得到了结果,但我认为这不是一种优雅的方式。

所以我想知道,有没有方便的方法呢?

2 个答案:

答案 0 :(得分:5)

更优雅和可扩展的方法是使用优先级队列,其中大小限制为N.使用最小堆优先级队列,我们​​可以继续向队列添加条目,直到大小达到N.对于每个条目后优先级队列的大小已达到N,将其添加到队列中,然后删除队列头部的元素(具有最小值)。在我们耗尽了HashMap中的所有条目之后,队列将包含前N个条目。

这种方法的优点是,即使整个HashMap无法适应内存,我们也可以将其分解为更小的块并使用这种方法。此外,如果我们有一个并发优先级队列,我们​​也可以同时从不同的HashMaps向队列中添加条目。

public static List<String> topNKeys(final HashMap<String, Double> map, int n) {
    PriorityQueue<String> topN = new PriorityQueue<String>(n, new Comparator<String>() {
        public int compare(String s1, String s2) {
            return Double.compare(map.get(s1), map.get(s2));
        }
    });

    for(String key:map.keySet()){
        if (topN.size() < n)
            topN.add(key);
        else if (map.get(topN.peek()) < map.get(key)) {
            topN.poll();
            topN.add(key);
        }
    }
    return (List) Arrays.asList(topN.toArray());
}

答案 1 :(得分:3)

你所做的就是好的;你将不得不在某个地方写一个自定义比较器,你使用它的地方很好。

但您的compare()方法中有错误:如果s1&gt;您返回0 s2,但是你应该只在数字相等的情况下这样做,如果s1> 1则返回负数。 S2。以下实现纠正了这一点。

更好(更简单)的实现是:

 public int compare(String s1, String s2) {
     return Double.compare(map.get(s2), map.get(s1)); //reverse order
 }