8
public final Comparator<String> ID_IGN_CASE_COMP = new Comparator<String>() {

        public int compare(String s1, String s2) {
            return s1.compareToIgnoreCase(s2);
        }
    };

private Map< String, Animal > _animals = new TreeMap< String, Animal >(ID_IGN_CASE_COMP);

我的问题是,如何使用方法 get(id) 忽略给定的比较器。我希望地图按不区分大小写进行排序,但是当我通过给定键获取值时,我希望它区分大小写。

4

7 回答 7

8

我认为答案很简单。实现您自己的比较器,该比较器执行不区分大小写的排序,但不会“A”和“a”返回 0……也对它们进行排序。

问题是您的比较器为 compare("A", "a") 情况返回 0,这意味着就地图而言,它是相同的键。

使用比较器,例如:

public final Comparator<String> ID_IGN_CASE_COMP = new Comparator<String>() {

    public int compare(String s1, String s2) {
        int result = s1.compareToIgnoreCase(s2);
        if( result == 0 )
            result = s1.compareTo(s2);
        return result;
    }
};

然后无论大小写,所有键都将进入,并且“a”和“A”仍将被排序在一起。

换句话说,get("a") 会给你一个与 get("A") 不同的值......并且它们都会出现在 keySet() 迭代器中。它们将被排序在一起。

于 2009-11-23T12:41:30.523 回答
7

在 TreeMap 中,添加两个键 a 和 b(按此顺序)以便 compare(a, b) 返回 0 将导致最新添加的条目 (b) 将覆盖第一个条目 (a)。

在您的情况下,这意味着不区分大小写的 get(id) 永远不会有任何用途。

引用http://java.sun.com/javase/6/docs/api/java/util/TreeMap.html

请注意,如果该排序映射要正确实现 Map 接口,则排序映射维护的排序(无论是否提供显式比较器)必须与 equals 一致。(参见 Comparable 或 Comparator 以获得与 equals 一致的精确定义。)这是因为 Map 接口是根据 equals 操作定义的,但是 map 使用它的 compareTo(或 compare)方法执行所有键比较,所以两个键从排序图的角度来看,这种方法认为相等的元素是相等的。已排序映射的行为是明确定义的,即使它的排序与 equals 不一致;它只是不遵守 Map 接口的一般合同。

这可能不是你想要的。

如果映射比较小并且您不需要多次获取已排序的条目,则解决方案是使用 HashMap(或未显式设置比较器的 TreeMap),并在需要时不区分大小写地对条目进行排序订购。

于 2009-11-23T12:12:53.123 回答
1

你需要一个多重映射:这个多重映射的每个条目都保留不区分大小写的键和另一个以原始键作为值的映射。

有许多可免费使用的多图实现,例如Common CollectionsGoogle Collections

于 2009-11-23T12:24:00.837 回答
1

为此,您必须使用两个单独的 TreeMap,其内容相同但比较器不同。

于 2009-11-23T12:01:10.733 回答
1

也许它会完成这项工作:

    new Comparator<String>(){
    public int compare(String s1, String s2)
    {
        String s1n = s1.toLowerCase();
        String s2n = s2.toLowerCase();

        if(s1n.equals(s2n))
        {
            return s1.compareTo(s2);
        }
        return s1n.compareTo(s2n);
    }
};
                                                    }
于 2009-11-23T12:05:48.817 回答
0

除了所有其他答案并同意之外,不可能有一个具有不同比较器的 TreeMap 结构:

根据您的问题,我了解到您有两个要求:数据模型应区分大小写(您在使用时需要区分大小写的值get()),演示者应不区分大小写(您需要区分大小写的排序,演示文稿只是一个假设) .

假设,我们用映射 (aa,obj1), (aA,obj2), (Aa,obj3), (AA,obj4) 填充 Map。迭代器将按顺序提供值:(obj4, obj3, obj2, obj1)(*)。现在,如果地图的排序不区分大小写,您期望哪个顺序?所有四个键都是相等的,并且顺序未定义。或者您是否正在寻找一种解决方案来解决键“AA”的集合 {obj1, obj2, obj3, obj4}?但这是一种不同的方法。

SO 鼓励社区诚实:因此我在这一点上的建议是再次查看您的要求:)

(*) 未经测试,假设 'A' < 'a' = true。

于 2009-11-23T13:21:46.933 回答
-1

在循环中使用floorEntryhighEntry以不区分大小写地查找条目;当您找到完全匹配的键时停止。

于 2009-11-23T12:08:09.643 回答