【问题标题】:How to write a custom Comparator for TreeMap in Java?如何在 Java 中为 TreeMap 编写自定义比较器?
【发布时间】:2019-06-28 01:58:18
【问题描述】:

我想将键值对存储在 TreeMap 中,并按照以下逻辑根据 Key 的值对条目进行排序:

按密钥长度排序。如果两个键的长度相同,则按字母顺序对其进行排序。例如,对于以下键值对。

IBARAKI MitoCity
TOCHIGI UtunomiyaCity
GUNMA MaehashiCity
SAITAMA SaitamaCity
CHIBA ChibaCity
TOKYO Sinjyuku
KANAGAWA YokohamaCity

预期的输出是这样的。

CHIBA : ChibaCity
GUNMA : MaehashiCity
TOKYO : Sinjyuku
IBARAKI : MitoCity
SAITAMA : SaitamaCity
TOCHIGI : UtunomiyaCity
KANAGAWA : YokohamaCity

【问题讨论】:

  • 请包括您迄今为止为实现此所做的工作
  • 你的排序标准是什么
  • 由于您没有提供任何代码并将其标记为 Java,我建议您阅读Comparator 接口及其.thenComparing 方法的文档
  • 问题>>短键名顺序,如果长度相同,按字典字母顺序排列
  • 请阅读How to create a Minimal, Complete, and Verifiable example 了解为什么我们总是要求提供代码。

标签: java comparator treemap


【解决方案1】:

您需要为此编写自己的comparator 并在TreeMap 中使用它,例如:

public class StringComparator implements Comparator<String> {

    @Override
    public int compare(String s1, String s2) {
        return s1.length() == s2.length() ? s1.compareTo(s2) : s1.length() - s2.length();
    }

    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
        Map<String, String> map = new TreeMap<>(new StringComparator());
        map.put("IBARAKI", "MitoCity");
        map.put("TOCHIGI", "UtunomiyaCity");
        map.put("GUNMA", "MaehashiCity");
        map.put("SAITAMA", "SaitamaCity");
        map.put("CHIBA", "ChibaCity");
        map.put("TOKYO", "Sinjyuku");
        map.put("KANAGAWA", "YokohamaCity");

        System.out.println(map);
    }

}

这不处理 null 值,但如果您在用例中期望 null 值,您可以添加处理。

【讨论】:

  • 另外:Integer.compare(s1.length(), s2.length()) 将是编写此比较方法的更简单方法(或放弃编写自己的类并使用 comparing(String::length))。
  • @AndyTurner 同意。这是我要说的另一种方法,由 OP 决定采用哪种方法。
【解决方案2】:

您可以将 Comparator 作为参数传递给 Map 的构造函数。 根据文档,它仅用于键:

/**
 * Constructs a new, empty tree map, ordered according to the given
 * comparator.  All keys inserted into the map must be <em>mutually
 * comparable</em> by the given comparator: {@code comparator.compare(k1,
 * k2)} must not throw a {@code ClassCastException} for any keys
 * {@code k1} and {@code k2} in the map.  If the user attempts to put
 * a key into the map that violates this constraint, the {@code put(Object
 * key, Object value)} call will throw a
 * {@code ClassCastException}.
 *
 * @param comparator the comparator that will be used to order this map.
 *        If {@code null}, the {@linkplain Comparable natural
 *        ordering} of the keys will be used.
 */
public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}

通过这种方式,您可以通过密钥长度传递比较器,如下所示:

new TreeMap<>(Comparator.comparingInt(String::length).thenComparing(Comparator.naturalOrder()))

【讨论】:

  • 哦,嘿,有人打败我发布Comparator 解决方案。比自己做实际物流要好得多 (o1 &lt; o2 barf)
【解决方案3】:

您应该创建一个唯一的比较器来比较地图的键。但是因为您也想打印这些值,所以您应该比较整个条目集:

Comparator<Map.Entry<String, String>> c = new Comparator<Map.Entry<String, String>>() {
  @Override
  public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
    int q = Integer.compare(o1.getKey().length(), o2.getKey().length());
    return q != 0 ? q : o1.getKey().compareTo(o2.getKey());
  }
};

那么你就可以在排序中使用这个比较器了:

map.entrySet().stream().sorted(c).forEach(System.out::println);

【讨论】:

    【解决方案4】:

    您可以按以下方式执行此操作。

      public static void main(String[] args) {
    
          Map<String, String> map = new TreeMap<>(new CustomSortComparator());
    
          map.put("IBARAKI", "MitoCity");
          map.put("TOCHIGI", "UtunomiyaCity");
          map.put("GUNMA", "MaehashiCity");
          map.put("SAITAMA", "SaitamaCity");
          map.put("CHIBA", "ChibaCity");
          map.put("TOKYO", "Sinjyuku");
          map.put("KANAGAWA", "YokohamaCity");
    
          System.out.println(map);
    
      }
    

    CustomSortComparator 的定义如下。

    public class CustomSortComparator implements Comparator<String> {
    
      @Override
      public int compare(String o1, String o2) {
        if (o1.length() > o2.length()) {
          return 1;
        }
        if (o1.length() < o2.length()) {
          return -1;
        }
        return returnCompareBytes(o1, o2);
      }
    
      private int returnCompareBytes(String key1, String key2) {
        for (int i = 0; i < key1.length() - 1; i++) {
          if (key1.charAt(i) > key2.charAt(i)) {
            return 1;
          }
          if (key1.charAt(i) < key2.charAt(i)) {
            return -1;
          }
        }
        return 0;
      }
    }
    
    

    【讨论】:

      【解决方案5】:

      可以使用这种方法,而不是直接将 Map 转换为 TreeMap

       public static Map toTreeMap(Map hashMap) 
          { 
              // Create a new TreeMap 
              Map treeMap = new TreeMap<>(new Comparator<Map.Entry<String, String>>(){
      
                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2 ) 
             {
                   if (o1.getKey().length() > o2.getKey().length()) {
                            return 1;
                      }
                  if (o1.getKey().length() > o2.getKey().length()) {
                            return -1;
                     }
                 return o1.getKey().compareTo(o2.getKey());
            }
      
            }); 
      
           for(Map.entry e : hashmap){
              treeMap.put(e.getKey(),e.getValue);
           }
      
      
              return treeMap; 
      
      }
      
      

      【讨论】:

        【解决方案6】:

        您可以在构造函数调用TreeMap中定义您需要的Comparator&lt;String&gt;

        import java.util.Comparator;
        import java.util.Map;
        import java.util.TreeMap;
        
        
        public class Main {
            static final Map<String, String> map = 
                    new TreeMap<String, String> (new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    int diff_length = o1.length() - o2.length();
                    if (diff_length != 0) return diff_length;
                    return o1.compareTo(o2);
                }
            });
        
            public static final void main(String[] args) {
                map.put("IBARAKI", "MitoCity");
                map.put("TOCHIGI", "UtunomiyaCity");
                map.put("GUNMA", "MaehashiCity");
                map.put("SAITAMA", "SaitamaCity");
                map.put("CHIBA", "ChibaCity");
                map.put("TOKYO", "Sinjyuku");
                map.put("KANAGAWA", "YokohamaCity");
        
                System.out.println(map);
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 2021-01-16
          • 2020-11-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-22
          • 1970-01-01
          • 1970-01-01
          • 2023-03-30
          相关资源
          最近更新 更多