Java的SortMap比较器,使得数字键在字母键之后排序

huangapple go评论74阅读模式
英文:

Java SortMap Comparator to have digit keys ordered after letter keys

问题

public static void main(String[] args) {
    SortedMap<Character, String> sortedMap = new TreeMap<>(new Comparator<Character>() {
        @Override
        public int compare(Character o1, Character o2) {
            if (Character.isDigit(o1) && Character.isLetter(o2)){
                return o2.compareTo(o1);
            }
            else if(Character.isLetter(o1) && Character.isDigit(o2)){
                return o1.compareTo(o2);
            }
            else{
                return o1.compareTo(o2);
            }
        }
    });

    sortedMap.put('5', "five");
    sortedMap.put('8', "nine");
    sortedMap.put('A', "ALPHA");
    sortedMap.put('G', "GOLF");
    sortedMap.put('F', "FOXTROT");
    System.out.println(sortedMap.values());
}
英文:

I need a SortedMap where the Charachter keys are sorted this way: ('A'..'Z'..'0'..'9'), so character first, then digits, all in ascending order.
This is what I have tried so far, however, the output shows it fails in returning the sorting I want, because the values of the digit keys are still before the values of letter keys.
What am I doing wrong? Is there an even better way to do this?
Thanks in advance!

public static void main(String[] args) {
    SortedMap&lt;Character, String&gt; sortedMap = new TreeMap&lt;&gt;(new Comparator&lt;Character&gt;() {
        @Override
        public int compare(Character o1, Character o2) {
            if (Character.isDigit(o1) &amp;&amp; Character.isLetter(o2)){
                return o2.compareTo(o1);
            }
            else if(Character.isLetter(o1) &amp;&amp; Character.isDigit(o2)){
                return o1.compareTo(o2);
            }
            else{
                return o1.compareTo(o2);
            }
        }
    });

    sortedMap.put(&#39;5&#39;, &quot;five&quot;);
    sortedMap.put(&#39;8&#39;, &quot;nine&quot;);
    sortedMap.put(&#39;A&#39;, &quot;ALPHA&quot;);
    sortedMap.put(&#39;G&#39;, &quot;GOLF&quot;);
    sortedMap.put(&#39;F&#39;, &quot;FOXTROT&quot;);
    System.out.println(sortedMap.values());
}

答案1

得分: 2

你需要在 o1 是数字而 o2 是字母的情况下返回结果 "o1 > o2",因此在这种情况下返回 1。类似地,如果 o1 是字母而 o2 是数字,你需要返回结果 "o1 < o2",即返回 -1。

public int compare(Character o1, Character o2) {
   if (Character.isDigit(o1) && Character.isLetter(o2)){
      return 1;
   }
   else if(Character.isLetter(o1) && Character.isDigit(o2)){
      return -1;
   }
   else{
      return o1.compareTo(o2);
   }
}
英文:

You need to return the result "o1 > o2" if o1 is a digit and o2 is a letter, so return 1 in this case. Similarly, if o1 is a letter and o2 is a digit, you need to return the result "o1 < o2", i.e. return -1.

public int compare(Character o1, Character o2) {
   if (Character.isDigit(o1) &amp;&amp; Character.isLetter(o2)){
      return 1;
   }
   else if(Character.isLetter(o1) &amp;&amp; Character.isDigit(o2)){
      return -1;
   }
   else{
      return o1.compareTo(o2);
   }
}

答案2

得分: 2

如果 o1 是一个字母而 o2 是一个数字,您应该始终返回 -1,因为您始终希望字母排在前面。而如果情况相反,您应该始终返回 1。

唯一的情况是在最后的 else 中应返回 o1.compareTo(o2),这意味着 o1o2 都是字母或数字,此时比较器应该简单地遵循自然顺序。

英文:

You should always return -1 if o1 is a letter and o2 is a digit, because you always want the letter to go first. And you should always return 1 if it's the opposite.

The only case where it should return o1.compareTo(o2) is in the final else, which means o1 and o2 are both either letters or numbers, and in that case, the comparator should simply follow natural order.

答案3

得分: 1

假设您使用的是 Java 8+,请将您的 Map 声明为:

SortedMap<Character, String> sortedMap = 
            new TreeMap<>(Comparator.comparingInt(c -> (c + 197) % 255));

可选地,您可以将 "magic numbers" 197 和 255 提取为常量,或将 comparingInt(..) 的参数提取为常量。

解释:
字符 0 到 9 对应 ASCII 码 48 到 57
所有字母的 ASCII 码属于范围 65 到 122
上述代码将代码稍微偏移,将数字范围移动到 245 到 254,字母范围移动到 7 到 64
由于比较器比较了偏移后的代码,所以它会将字母排在数字之前

英文:

Asusuming you're using Java 8+, declare your Map as:

SortedMap&lt;Character, String&gt; sortedMap = 
            new TreeMap&lt;&gt;(Comparator.comparingInt(c -&gt; (c + 197) % 255));

Optionally, you can extract "magic numbers" 197 and 255 into constants, or extract argument of comparingInt(..) into a constant.

Explanation:
chars 0..9 correspond to ASCII codes 48..57
ASCII codes for all the letters belong to range 65..122
Code above shifts codes a bit, moving numbers range to 245..254 and letters range to 7..64
Since Comparator compares shifted codes, it places letters before digits

答案4

得分: 0

public int compare(Character o1, Character o2) {
    if (Character.isDigit(o1) && Character.isLetter(o2)) {
        // o1 < o2 regardless of what values o1 and o2 are
        // So return any negative integer
        return -100;
    }
    else if (Character.isLetter(o1) && Character.isDigit(o2)) {
        // o1 > o2 regardless of what values o1 and o2 are
        // So return any positive integer
        return 100;
    }
    // Both must be letters or both must be integers
    // fall back to normal comparison, as you have already done
    return o1.compareTo(o2);
}
英文:

When you want all letters to come before all digits, and you get one digit and one letter, you should not be comparing them at all:

public int compare(Character o1, Character o2) {
    if (Character.isDigit(o1) &amp;&amp; Character.isLetter(o2)) {
        // o1 &lt; o2 regardless of what values o1 and o2 are
        // So return any negative integer
        return -100;
    }
    else if (Character.isLetter(o1) &amp;&amp; Character.isDigit(o2)) {
        // o1 &gt; o2 regardless of what values o1 and o2 are
        // So return any positive integer
        return 100;
    }
    // Both must be letters or both must be integers
    // fall back to normal comparison, as you have already done
    return o1.compareTo(o2);
}

答案5

得分: 0

我更喜欢在 Map 的声明外部使用 ternary (?:) 结构来构建 Comparator。我还添加了一些额外的值,与您的值交替,以增加变化性。

		Comparator<Character> comp = (a, b) -> Character.isLetter(a)
				&& Character.isDigit(b) ? -1 :
				Character.isLetter(b) && Character.isDigit(a) ? 1 :
				a.compareTo(b);
		
		SortedMap<Character, String> sortedMap = new TreeMap<>(comp);
		sortedMap.put('Q', "Quebec");
		sortedMap.put('B', "Beta");
		sortedMap.put('5', "five");
		sortedMap.put('9', "nine");
		sortedMap.put('A', "ALPHA");
		sortedMap.put('3', "three");
		sortedMap.put('G', "GOLF");
		sortedMap.put('F', "FOXTROT");
		sortedMap.entrySet().forEach(System.out::println);

打印输出结果为:

A=ALPHA
B=BETA
F=FOXTROT
G=GOLF
Q=QUEBEC
3=three
5=five
9=nine
英文:

I prefer using a ternary (?:) construction outside the Map declaration to build the Comparator. I also added some extra values interspersed with yours to add variability.

		Comparator&lt;Character&gt; comp = (a, b) -&gt; Character.isLetter(a)
				&amp;&amp; Character.isDigit(b) ? -1 :
				Character.isLetter(b) &amp;&amp; Character.isDigit(a) ? 1 :
				a.compareTo(b);
		
		SortedMap&lt;Character, String&gt; sortedMap = new TreeMap&lt;&gt;(comp);
		sortedMap.put(&#39;Q&#39;, &quot;Quebec&quot;);
		sortedMap.put(&#39;B&#39;, &quot;Beta&quot;);
		sortedMap.put(&#39;5&#39;, &quot;five&quot;);
		sortedMap.put(&#39;9&#39;, &quot;nine&quot;);
		sortedMap.put(&#39;A&#39;, &quot;ALPHA&quot;);
		sortedMap.put(&#39;3&#39;, &quot;three&quot;);
		sortedMap.put(&#39;G&#39;, &quot;GOLF&quot;);
		sortedMap.put(&#39;F&#39;, &quot;FOXTROT&quot;);
		sortedMap.entrySet().forEach(System.out::println);

Prints


A=ALPHA
B=BETA
F=FOXTROT
G=GOLF
Q=QUEBEC
3=three
5=five
9=nine

</details>



huangapple
  • 本文由 发表于 2020年4月4日 10:21:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/61023041.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定