【问题标题】:In Java, sort hash map by its key.length()在 Java 中,通过 key.length() 对 hashmap 进行排序
【发布时间】:2014-11-12 01:00:46
【问题描述】:

我有一个这样的哈希图:

HashMap<String,Integer> map = new HashMap<String,Integer>();
map.put("java",4);
map.put("go",2);
map.put("objective-c",11);
map.put("c#",2);

现在我想按它的键长度对这个映射进行排序,如果两个键长度相等(例如 go 和 c# 都长度为 2),然后按 alphba 顺序排序。 所以我期望得到的结果是这样的:

打印结果: 目标-c,11 爪哇,4 时间,2 走吧,2

这是我自己的attamp,但它根本不起作用......

      HashMap<String,Integer> map = new HashMap<String,Integer>();
          map.put("java",4);
          map.put("go",2);
          map.put("objective-c",11);
          map.put("c#",2);

      Map<String,Integer> treeMap = new TreeMap<String, Integer>(
                new Comparator<String>() {
                    @Override
                    public int compare(String s1, String s2) {
                        return s1.length().compareTo(s2.length());
                    }
                }
        );

实际上 'compareTo' 方法显示为红色(无法编译).... 请有人帮我提供一些代码示例...我对如何使用比较器类来自定义比较对象有点困惑...

【问题讨论】:

    标签: java sorting hashmap comparator treemap


    【解决方案1】:

    编译器正在抱怨,因为您不能在 int 上调用 compareTo。对地图进行排序的正确方法如下:

    Map<String, Integer> treeMap = new TreeMap<String, Integer>(
        new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                if (s1.length() > s2.length()) {
                    return -1;
                } else if (s1.length() < s2.length()) {
                    return 1;
                } else {
                    return s1.compareTo(s2);
                }
            }
    });
    

    前两个条件比较两个Strings 的长度,并相应地返回一个正数或负数。第三个条件将比较 Strings 的长度是否相等。

    【讨论】:

      【解决方案2】:

      您调用String#length(),它返回一个原语int。您需要静态方法Integer.compare(int,int)。如果您使用的是 Java 8,则可以节省大量输入:

      Map<String,Integer> treeMap = new TreeMap<>(
              Comparator.comparingInt(String::length)
                        .thenComparing(Function.identity()));
      

      【讨论】:

      • 先生,您的输出是 {}?
      • 我的代码不会尝试任何输出,但如果您询问的是空地图的字符串表示形式,那么您是对的。
      • 我发布了这个问题。如果你能回答stackoverflow.com/questions/25905445/…
      • 这个答案不正确,如果你有两个键"Foo""foo",即相同的长度和不同大小写的相同字母,那么第二个 put 将覆盖第一个,这就是为什么有如果长度相等,则应该是字典比较。
      • @A4L 没错,这是一个遗漏。我更新了答案,以便比较回退到默认字符串比较。
      【解决方案3】:
      public int compare(String o1, String o2) {
        return o1.length() == o2.length() ? o1.compareTo(o2) : o1.length() - o2.length();
      }
      

      【讨论】:

        【解决方案4】:

        因为length() 没有定义compareTo 方法,这就是您看到错误的原因。要更正它,请使用下面的 Integer.compare(s1.length(), s2.length()); 更新代码

        import java.util.Comparator;
        import java.util.HashMap;
        import java.util.Map;
        import java.util.TreeMap;
        
        public class Test {
        
            public static void main(String[] args) {
        
                HashMap<String,Integer> map = new HashMap<String,Integer>();
                map.put("java",4);
                map.put("go",2);
                map.put("objective-c",11);
                map.put("c#",2);
        
        
                Map<String,Integer> treeMap = new TreeMap<String, Integer>(
                        new Comparator<String>() {
                            @Override
                            public int compare(String s1, String s2) {
                                return Integer.compare(s1.length(), s2.length());
                            }
                        }
                );
        
                treeMap.putAll(map);
        
                System.out.println(treeMap);
            }
        }
        

        【讨论】:

        • 运行代码时,结果为 {c#=2, java=4,objective-c=11}。问题是“去”在哪里,2?
        • 这是因为 TreeMap 使用了 Comparator 并且比较器被定义为将 2 个相等长度的字符串视为相同。由于 OP 正在使用 TreeMap,所以我扩展了他/她的答案以仅更正 Comparator 部分。
        • 很酷,你觉得我的回答怎么样?由于操作没有提到使用树图是强制性的,所以我使用了另一种样式
        • 代码没有按预期工作,相同长度的键被覆盖
        【解决方案5】:

        如果使用 TreeMap 不是强制性的

        解释:定义一个Comaprator,下一步,定义一个列表,以便我们可以将所有映射条目添加到列表中。最后,按照定义的Comaprator对列表进行排序

        代码

         Comparator<Map.Entry<String,Integer>> byMapValues = 
                 (Map.Entry<String,Integer> left, Map.Entry<String,Integer> right) ->left.getValue().compareTo(right.getValue());
        
         List<Map.Entry<String,Integer>> list = new ArrayList<>();
         list.addAll(map.entrySet());
         Collections.sort(list, byMapValues);
         list.forEach( i -> System.out.println(i));
        

        输出

        c#=2
        go=2
        java=4
        objective-c=11
        

        注意:按数字排序

        如果需要根据key做比较,可以使用下面这行。

        Comparator<Map.Entry<String,Integer>> byMapKeys = 
                     (Map.Entry<String,Integer> left, Map.Entry<String,Integer> right) -> left.getKey().compareTo(right.getKey());
        

        【讨论】:

          【解决方案6】:

          比较器应该是:

          new Comparator<String>() {
              @Override
              public int compare(String s1, String s2) {
                  return Integer.compare(s1.length(), s2.length());
              }
          }
          

          【讨论】:

          • 不起作用。如果两个字符串长度相同,并且使用 TreeMap 进行排序,它会将长度相同的字符串键视为重复项并删除它们。
          猜你喜欢
          • 1970-01-01
          • 2017-09-22
          • 1970-01-01
          • 2020-12-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-21
          • 2017-11-12
          相关资源
          最近更新 更多