Java SortedMap Comparator 让数字键在字母键之后排序
Java SortMap Comparator to have digit keys ordered after letter keys
我需要一个 SortedMap,其中字符键按以下方式排序:('A'..'Z'..'0'..'9'),所以首先是字符,然后是数字,全部按升序排列。
这是我到目前为止所尝试的,但是,输出显示它无法返回我想要的排序,因为数字键的值仍然在字母键的值之前。
我究竟做错了什么?有没有更好的方法来做到这一点?
提前致谢!
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());
}
如果 o1 是数字且 o2 是字母,则需要 return 结果 "o1 > o2",因此在本例中为 return 1。同理,如果o1是字母,o2是数字,需要return结果"o1 < o2",即return -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);
}
}
如果 o1
是一个字母并且 o2
是一个数字,你应该总是 return -1,因为你 总是 想要字母先走。如果相反,你应该总是 return 1 。
唯一应该return o1.compareTo(o2)
的情况是最后的else
,这意味着o1
和o2
要么是字母要么是数字,在那种情况下,比较器应该简单地遵循自然顺序。
当您希望所有字母都出现在所有数字之前,并且您得到一位数字和一个字母时,您根本不应该比较它们:
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);
}
我更喜欢在 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
假设您使用的是 Java 8+,请将您的地图声明为:
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
由于 Comparator 比较移位后的代码,它会将字母放在数字之前
我需要一个 SortedMap,其中字符键按以下方式排序:('A'..'Z'..'0'..'9'),所以首先是字符,然后是数字,全部按升序排列。 这是我到目前为止所尝试的,但是,输出显示它无法返回我想要的排序,因为数字键的值仍然在字母键的值之前。 我究竟做错了什么?有没有更好的方法来做到这一点? 提前致谢!
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());
}
如果 o1 是数字且 o2 是字母,则需要 return 结果 "o1 > o2",因此在本例中为 return 1。同理,如果o1是字母,o2是数字,需要return结果"o1 < o2",即return -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);
}
}
如果 o1
是一个字母并且 o2
是一个数字,你应该总是 return -1,因为你 总是 想要字母先走。如果相反,你应该总是 return 1 。
唯一应该return o1.compareTo(o2)
的情况是最后的else
,这意味着o1
和o2
要么是字母要么是数字,在那种情况下,比较器应该简单地遵循自然顺序。
当您希望所有字母都出现在所有数字之前,并且您得到一位数字和一个字母时,您根本不应该比较它们:
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);
}
我更喜欢在 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
假设您使用的是 Java 8+,请将您的地图声明为:
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
由于 Comparator 比较移位后的代码,它会将字母放在数字之前