如何按照值对 HashMap 的元素进行排序?

7
我有以下的 HashMap
HashMap<String, Integer> counts = new HashMap<String, Integer>();

什么是根据值排序的最简单方法?

1
你不能对HashMap进行排序,但是你可以使用TreeMap,但是键和值必须互换以满足你的需求。 - Bhesh Gurung
请忽略我之前评论中的建议。问题在于可能会有多个计数相同的条目,而映射不允许重复键。我认为最好的方法是遵循那些对列表进行排序的答案建议。 - Bhesh Gurung
如果您不受限于使用 HashMap,为什么不创建一个包含单词作为 String、计数作为 int 的类,并实现 Comparable 接口以查找最大值,然后将所有这些对象插入到最大堆中,并找到堆的根节点呢? - Zéychin
4个回答

9

您无法按值对Map进行排序,尤其是HashMap根本无法排序。

相反,您可以对条目进行排序:

List<Map.Entry<String, Integer>> entries = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
  public int compare(
      Map.Entry<String, Integer> entry1, Map.Entry<String, Integer> entry2) {
    return entry1.getValue().compareTo(entry2.getValue());
  }
});

将会按照计数的升序对条目进行排序。


4
你可以通过使用map.entrySet()从地图中获取一组条目(Set of Map.Entry)。只需对它们进行迭代,并通过getValue()检查值即可。请注意,保留HTML标签。

1

TreeMap可以按照Comparator定义的顺序保留其条目。

  1. 我们可以创建一个比较器,通过将最大值放在第一位来对Map进行排序。
  2. 然后,我们将构建一个使用该比较器的TreeMap。
  3. 接下来,我们将把所有条目放入我们的counts映射中。
  4. 最后,我们将获取地图中的第一个键,这应该是最常见的单词(如果有多个单词计数相等,则至少是其中之一)。

    public class Testing {
        public static void main(String[] args) {
    
            HashMap<String,Double> counts = new HashMap<String,Integer>();
    
            // 样本单词计数
            counts.put("the", 100);
            counts.put("pineapple",5);
            counts.put("a", 50);
    
            // 步骤1:创建一个比较器,按最大值排序
            MostCommonValueFirst mostCommonValueFirst =  new MostCommonValueFirst(counts);
    
            // 步骤2:构建一个使用该比较器的TreeMap
            TreeMap<String,Double> sortedMap = new TreeMap<String,Integer (mostCommonValueFirst);
    
            // 步骤3:用计数映射中的值填充TreeMap
            sortedMap.putAll(counts);
    
            // 步骤4:地图中的第一个键是最常用的单词
            System.out.println("Most common word: " + sortedMap.firstKey());
        }
    }
    
    private class MostCommonValueFirst implements Comparator<String> {
       Map<String, Integer> base;
    
       public MostCommonValueFirst(Map<String, Integer> base) {
          this.base = base;
       }
    
       // 注意:此比较器施加的排序与相等不一致。
       public int compare(String a, String b) {
          if (base.get(a) >= base.get(b)) {
              return 1;
          } else {
             return -1;
          } // 返回0将合并键
       }
     }
    

来源:https://dev59.com/qXVD5IYBdhLWcg3wDG_m#1283722


我不确定这是否是一个好主意。键的比较器顺序可以随着映射的值而改变。就TreeMap而言,它本质上是一个可变的键。 - Steve Kuo
同意,但我们仍然可以在填充地图后再做这件事。 - Adam

1

如果您想按顺序打印它们(而不是存储),则可以使用以下解决方法:

  1. 创建一个新的Map(tempMap),将您的值作为键,将键作为值。为了使键唯一,请在每个键中添加一些唯一值,例如key1 = value1+@0。

  2. 将值列表作为map.values()获取到列表myVlues中。

  3. myVlues列表进行排序,使用Collections.sort(myVlues)

  4. 现在迭代myVlues,从tempMap获取相应的key,恢复键,例如key.substring(0,key.length-2),然后打印键和值对。

希望这可以帮助您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接