Java TreeMap(比较器)和get方法忽略了比较器

时间:2009-11-23 11:51:35

标签: java comparator treemap

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)忽略给定的比较器。我希望地图按Case Insensitive排序,但是,当我按给定键获取值时,我希望它区分大小写。

7 个答案:

答案 0 :(得分:8)

我认为答案很简单。实现你自己的比较器,它做一个不区分大小写的排序,但 NOT 为“A”和“a”返回0 ......也对它们进行排序。

问题是你的比较器为比较(“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()迭代器中。它们将被整理在一起。

答案 1 :(得分:6)

在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而不显式设置比较器),并在不区分大小写的情况下对条目进行排序。你需要他们订购。

答案 2 :(得分:1)

你必须使用两个独立的TreeMaps,内容相同但比较器不同。

答案 3 :(得分: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);
    }
};
                                                    }

答案 4 :(得分:1)

您需要一个多图:此多图的每个条目都会保留不区分大小写键,另一个图标以原始键作为值。

有许多可自由使用的多重映射实现,例如Common CollectionsGoogle Collections

答案 5 :(得分:0)

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

根据您的问题,我了解您有两个要求:数据模型应区分大小写(使用get()时需要区分大小写的值),演示者不区分大小写(您希望区分大小写)订购,演示只是一个假设。)

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

SO鼓励社区诚实:因此,我的建议是再次查看您的要求:)

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

答案 6 :(得分:-1)

在循环中使用floorEntry然后higherEntry来查找不区分大小写的条目;当你找到确切的钥匙匹配时停止。