简体   繁体   English

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

[英]Java TreeMap (comparator) and get method ignoring the comparator

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);

My problem is, how to use method get(id) ignoring the given comparator. 我的问题是,如何使用方法get(id)忽略给定的比较器。 I want the map to be order by Case Insensitive but, I want it to be case sensitive when I fetch the values by a given key. 我希望地图按Case Insensitive排序,但是,当我通过给定键获取值时,我希望它区分大小写。

I think the answer is easy. 我认为答案很简单。 Implement your own comparator that does a case insensitive sort but does NOT return 0 for "A" and "a"... sort them too. 实现自己的比较,做一个不区分大小写的排序但对于“A”和“A” ...太对它们进行排序返回0。

The issue is that your comparator returns 0 for the compare( "A", "a" ) case which means it is the same key as far as the map is concerned. 问题是你的比较器为比较(“A”,“a”)情况返回0,这意味着就地图而言它是相同的密钥。

Use a comparator like: 使用比较器,如:

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;
    }
};

Then all keys will go in regardless of case and "a" and "A" will still be sorted together. 然后,无论大小写如何,所有键都将进入,“a”和“A”仍将一起排序。

In other words, get("a") will give you a different value from get("A")... and they will both show up in keySet() iterators. 换句话说,get(“a”)将为您提供与get(“A”)不同的值...并且它们都将显示在keySet()迭代器中。 They will just be sorted together. 它们将被整理在一起。

In a TreeMap, adding two keys a and b (in that order) so that compare(a, b) returns 0 will result in that the latest added entry (b) will overwrite the first one (a). 在TreeMap中,添加两个键a和b(按此顺序)以使compare(a,b)返回0将导致最新添加的条目(b)将覆盖第一个(a)。

In your case, this means that there will never be any use for case insensitive get(id). 在您的情况下,这意味着永远不会有任何使用不区分大小写的get(id)。

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

Note that the ordering maintained by a sorted map (whether or not an explicit comparator is provided) must be consistent with equals if this sorted map is to correctly implement the Map interface. 请注意,如果此有序映射要正确实现Map接口,则由有序映射维护的排序(无论是否提供显式比较器)必须与equals一致。 (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Map interface is defined in terms of the equals operation, but a map performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal. (请参阅Comparable或Comparator以获得与equals一致的精确定义。)这是因为Map接口是根据equals操作定义的,但是map使用compareTo(或compare)方法执行所有键比较,因此有两个键从排序地图的角度来看,通过这种方法被视为相等的是相等的。 The behavior of a sorted map is well-defined even if its ordering is inconsistent with equals; 即使排序与equals不一致,也可以很好地定义有序映射的行为。 it just fails to obey the general contract of the Map interface. 它只是不遵守Map接口的一般合同。

This is probably not what you want. 这可能不是你想要的。

If the map is comparably small and you don't need to fetch the sorted entries very many times, a solution is to use a HashMap (or a TreeMap without explicitly setting the comparator), and sort the entries case-insensitively when you need them ordered. 如果地图相对较小并且您不需要多次获取已排序的条目,则解决方案是使用HashMap(或TreeMap而不显式设置比较器),并在需要时对条目不敏感地对条目进行排序订购。

您必须使用两个单独的TreeMaps,具有相同的内容但不同的比较器。

maybe it'll do the job: 也许它会完成这项工作:

    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);
    }
};
                                                    }

you need a multimap : each entry of this multimap keeps the case insensitive keys and aanother map with the original keys as value. 你需要一个multimap :这个multimap的每个条目都保持不区分大小写的键,另一个映射使用原始键作为值。

There are many freely usable implementations of multimaps such as Common Collections , Google Collections , etc 有许多可自由使用的多重映射实现,例如Common CollectionsGoogle Collections

In addition to all the other answers and agreeing, that it is impossible to have a single TreeMap structure with different comparators: 除了所有其他答案并同意之外,不可能有一个具有不同比较器的TreeMap结构:

From your question I understand that you have two requirements: the data model shall be case sensitive (you want the case sensitive values when you use get() ), the presenter shall be case insensitive (you want an case sensitive ordering, presentation is just an assumption). 根据您的问题,我了解您有两个要求:数据模型应区分大小写(当您使用get()时需要区分大小写的值),演示者应区分大小写(您希望区分大小写,演示文稿只是一个假设)。

Let's assume, we populate the Map with the mappings (aa,obj1), (aA,obj2), (Aa,obj3), (AA,obj4). 让我们假设,我们使用映射(aa,obj1),(aA,obj2),(aa,obj3),(AA,obj4)填充Map。 The iterator will provides the values in the order: (obj4, obj3, obj2, obj1)(*). 迭代器将按以下顺序提供值:(obj4,obj3,obj2,obj1)(*)。 Now which order do you expect if the map was ordered case-insensitive? 如果地图被排序为不区分大小,那么您现在期望哪个订单? All four keys would be equal and the order undefined. 所有四个键都相等,顺序未定义。 Or are you looking for a solution that would resolve the collection {obj1, obj2, obj3, obj4} for the key 'AA'? 或者您正在寻找一个解决方案,解决关键'AA'的集合{obj1,obj2,obj3,obj4}? But that's a different approach. 但这是一种不同的方法。

SO encourages the community to be honest: therefore my advice at this point is to look at your requirement again :) SO鼓励社区诚实:因此我的建议是再次查看您的要求:)

(*) not tested, assumed that 'A' < 'a' = true. (*)未经测试,假设'A'<'a'=真。

Use floorEntry and then higherEntry in a loop to find the entries case-insensitively; 使用floorEntry然后higherEntry在循环中找到的条目不区分大小写; stop when you find the exact key match. 找到确切的关键匹配时停止。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM