【问题标题】:Java How to return top 10 items based on value in a HashMapJava如何根据HashMap中的值返回前10个项目
【发布时间】:2013-06-10 07:28:51
【问题描述】:

所以我对 Java 非常陌生,因此我正在努力完成一项练习,将我的一个 Python 程序转换为 Java。

我遇到了一个问题,我试图复制该行为,从 python 中,以下将只返回按值排序的键,而不是值:

popular_numbers = sorted(number_dict, key = number_dict.get, reverse = True)

在 Java 中,我进行了一些研究,但还没有为像我这样的 n00b 或类似方法找到足够简单的示例。我找到了使用 Guava 进行排序的示例,但排序似乎返回了一个按键排序的 HashMap。

除了上述之外,我在 Java 中没有发现的关于 Python 的其他优点之一是能够轻松返回已排序值的子集。在 Python 中,我可以简单地执行以下操作:

print "Top 10 Numbers: %s" % popular_numbers[:10]

在本例中,number_dict 是键值对的字典,其中键表示数字 1..100,值是数字(键)出现的次数:

for n in numbers:
 if not n == '':
   number_dict[n] += 1

最终结果会是这样的:

前 10 位数字:['27', '11', '5', '8', '16', '25', '1', '24', '32', '20']

澄清一下,在 Java 中我成功地创建了一个 HashMap,我成功地检查了数字并增加了键值对的值。我现在卡在排序并根据值返回前 10 个数字(键)。

【问题讨论】:

标签: java sorting


【解决方案1】:
  1. 将地图的entrySet() 放入List
  2. 使用Collections.sortComparator 对这个列表进行排序,Entrys 根据它们的值排序。
  3. 使用ListsubList(int, int) 方法检索包含前10 个元素的新列表。

是的,它会比 Python 更冗长:)

【讨论】:

  • 是的,这就是要走的路。但是那么使用HashMap 有什么意义呢?特别是当结果按 value 排序时?我不知道OP在做什么......
【解决方案2】:

使用 Java 8+,获取整数列表的前 10 个元素:

list.stream().sorted().limit(10).collect(Collectors.toList());

要获取地图键的前 10 个元素,即整数:

map.keySet().stream().sorted().limit(10).collect(Collectors.toMap(Function.identity(), map::get));

【讨论】:

    【解决方案3】:

    HashMaps 没有在 Java 中排序,因此没有一个很好的方法来对它们进行排序,而不是通过所有键进行暴力搜索。尝试使用TreeMaphttp://docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html

    【讨论】:

    • TreeMap 基于键而非值进行排序。
    【解决方案4】:

    假设您的地图是这样定义的,并且您希望根据进行排序:

    HashMap<Integer, Integer> map= new HashMap<Integer, Integer>();
    //add values
    Collection<Integer> values= map.values();
    ArrayList<Integer> list= new ArrayList<Integer>(values);
    Collections.sort(list);
    

    现在,打印列表的前 10 个元素。

    for (int i=0; i<10; i++) {
        System.out.println(list.get(i));
    }
    

    map 中的值实际上没有排序,因为HashMap 根本没有排序(它根据键的 hashCode 将值存储在桶中)。此代码仅显示地图中的 10 个最小元素。

    EDIT 排序而不丢失键值对:

    //sorted tree map
    TreeMap<Integer, Integer> tree= new TreeMap<>();
    
    //iterate over a map
    Iteartor<Integer> it= map.keySet().iterator();
    while (it.hasNext()) {
        Integer key= it.next();
        tree.put(map.get(key), key);
    }
    

    现在您有了已排序的 TreeMap 树,并且从原始映射中反转了键值对,因此您不会丢失信息。

    【讨论】:

    • 现在您已经丢失了键值对
    • 这按值排序,但不会让您轻松查找它们以查看它们引用的键...
    • 是的,绑定丢失了,但如果您只需要前 10 个元素,它就会起作用。
    【解决方案5】:

    尝试下一个:

    public static void main(String[] args) {
    
        // Map for store the numbers
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
    
        // Populate the map ...
    
        // Sort by the more popular number
        Set<Entry<Integer, Integer>> set = map.entrySet();
        List<Entry<Integer, Integer>> list = new ArrayList<>(set);
        Collections.sort(list, new Comparator<Entry<Integer, Integer>>() {
            @Override
            public int compare(Entry<Integer, Integer> a,
                    Entry<Integer, Integer> b) {
                return b.getValue() - a.getValue();
            }
        });
    
    
        // Output the top 10 numbers
        for (int i = 0; i < 10 && i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    
    }
    

    【讨论】:

    • 在比较中使用b.getValue().compareTo(a.getValue())会更好。 OP 的示例使用整数,但如果他们决定放入一些浮点数,只需更改类型就会破坏此代码。
    • value 是一个数字的流行度(数字可能是浮动的)。换句话说,频率.
    • 好吧,我看到在这种情况下它只是整数。不过,我还是会坚持我的建议。
    【解决方案6】:

    Guava Multiset 非常适合您的用例,可以很好地替换您的 HashMap。它是一个统计每个元素出现次数的集合。

    Multisets 有一个方法copyHighestCountFirst,它返回一个按计数排序的不可变 Multiset。

    现在一些代码:

    Multiset<Integer> counter = HashMultiset.create();
    //add Integers 
    ImmutableMultiset<Integer> sortedCount = Multisets.copyHighestCountFirst(counter);
    //iterate through sortedCount as needed
    

    【讨论】:

      【解决方案7】:

      使用SortedMap,致电values()。文档指出以下内容:

      The collection's iterator returns the values in ascending order of the corresponding keys

      只要您的比较器编写正确,您就可以遍历第一个 n

      【讨论】:

        【解决方案8】:
        1. 从键集构建一个列表。

        2. 使用键对 HashMap 进行排序,以访问 Collection.sort() 方法中的值。

        3. 返回已排序键集的子列表。

        4. 如果您关心值,可以使用第 3 步中的键并构建值集。

          HashMap hashMap = new HashMap(); List list = new ArrayList(hashMap.keySet()); Collections.sort(list, (w1, w2) -> hashMap.get(w2) - hashMap.get(w1)); //按值降序排序;

          return list.subList(0, 10);

        【讨论】:

          【解决方案9】:

          为了保留排名顺序并高效返回top count,远小于map size的大小:

          map.entrySet().stream()
                      .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                      .limit(count)
                      .collect(toMap(Map.Entry::getKey, Map.Entry::getValue,
                              (e1, e2) -> e1,
                              LinkedHashMap::new))
          

          【讨论】:

            猜你喜欢
            • 2017-08-10
            • 1970-01-01
            • 1970-01-01
            • 2019-12-08
            • 2012-04-12
            • 1970-01-01
            • 2021-12-09
            • 2020-03-08
            • 2021-02-06
            相关资源
            最近更新 更多