我正在尝试使用排序键创建Map
,按字母顺序排序,最后按数字排序。为此,我使用TreeMap
和自定义Comparator
:
public static Comparator<String> ALPHA_THEN_NUMERIC_COMPARATOR =
new Comparator<String> () {
@Override
public int compare(String first, String second) {
if (firstLetterIsDigit(first)) {
return 1;
} else if (firstLetterIsDigit(second)) {
return -1;
}
return first.compareTo(second);
}
};
private static boolean firstLetterIsDigit(String string) {
return (string == null) ? false : Character.isDigit(string.charAt(0));
}
我写了下面的单元测试来说明出了什么问题:
@Test
public void testNumbericallyKeyedEntriesCanBeStored() {
Map<String, String> map = new HashMap<>();
map.put("a", "some");
map.put("0", "thing");
TreeMap<String, String> treeMap = new TreeMap<>(ALPHA_THEN_NUMERIC_COMPARATOR);
treeMap.putAll(map);
assertEquals("some", treeMap.get("a"));
assertEquals("thing", treeMap.get("0"));
}
结果:
java.lang.AssertionError:
Expected :thing
Actual :null
答案 0 :(得分:6)
检查您的比较器代码。比较“0”和“0”是否会返回0,应该如何?不,它没有,因为如果您的字符串以数字开头,则不检查是否相等。如果两个字符串都以数字开头,则也不会返回正确的顺序。
答案 1 :(得分:1)
对Comparator
的有效实施有一些要求。引自文档:
当且仅当
c.compare(e1, e2)==0
具有与e1.equals(e2)
相同的布尔值时,比较器c对一组元素S施加的排序被称为与等于一致对于e1
中的每个e2
和S
。
您的比较器不是这种情况:comparator.compare("0","0")
会在您的情况下返回1
。
进一步说:
当使用能够强加与equals不一致的排序的比较器来排序有序集(或有序映射)时,应该小心。假设具有显式比较器c的有序集(或有序映射)与从集合S中绘制的元素(或键)一起使用。如果由S对S施加的排序与equals,排序集(或已排序)不一致()#34; 特别是有序集(或有序映射)将违反集合(或映射)的一般契约,它以等于的方式定义。
(强调我 - 你可以替换&#34;奇怪地&#34;和#34;怪异&#34;,对于你的情况; - )
关于如何实施这种比较的细节,有一定程度的自由。例如。像"123isNotNumeric"
这样的密钥会发生什么?应该&#34;数字&#34;总是个位数?它们应该总是整数吗?
但是,一种可能的实现可能如下所示:
public class SpacialTreeSetComparator
{
public static void main(String[] args)
{
TreeMap<String, String> map = new TreeMap<String, String>(
ALPHA_THEN_NUMERIC_COMPARATOR);
map.put("b", "x");
map.put("a", "x");
map.put("1", "x");
map.put("0", "x");
System.out.println(map.keySet());
}
public static Comparator<String> ALPHA_THEN_NUMERIC_COMPARATOR =
new Comparator<String> () {
@Override
public int compare(String first, String second) {
Double firstNumber = asNumber(first);
Double secondNumber = asNumber(second);
if (firstNumber != null && secondNumber != null)
{
return firstNumber.compareTo(secondNumber);
}
if (firstNumber != null)
{
return 1;
}
if (secondNumber != null)
{
return -1;
}
return first.compareTo(second);
}
private Double asNumber(String string)
{
try
{
return Double.parseDouble(string);
}
catch (NumberFormatException e)
{
return null;
}
}
};
}
打印地图的keySet()
按所需顺序打印键:
[a, b, 0, 1]
答案 2 :(得分:0)
压缩机代码不正确。在treeMap.get(“0”)的情况下,不满足等式。
压缩器中的以下代码不正确并导致问题。当您从MAP获取某些元素(以查找匹配的键)时,也会调用压缩器。在“0”的情况下,你的字母数字代码返回true,如果条件返回1则跟随,所以它永远不会为“0”找到“0”相等为真,这就是返回NULL的原因。
if (firstLetterIsDigit(first)) {
return 1;
} else if (firstLetterIsDigit(second)) {
return -1;
}