Java TreeMap (comparator) и метод get игнорируют компаратор

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), игнорируя данный компаратор. Я хочу, чтобы карта была нечувствительной к регистру, но я хочу, чтобы она была чувствительной к регистру, когда я получаю значения данным ключом.

7 ответов


Я думаю, что ответ прост. Реализуйте свой собственный компаратор, который делает сортировку без учета регистра, но делает не возврат 0 для "A"и " a"... сортируйте их тоже.

проблема в том, что ваш компаратор возвращает 0 для случая сравнения( "A", "a"), что означает, что это тот же ключ, что и для карты.

используйте компаратор, например:

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 (). Они просто будут отсортированы вместе.


в TreeMap добавление двух ключей a и b (в этом порядке), так что compare(a, b) возвращает 0, приведет к тому, что последняя добавленная запись (b) перезапишет первую (a).

в вашем случае это означает, что никогда не будет никакого использования для нечувствительного к регистру get(id).

цитирование http://java.sun.com/javase/6/docs/api/java/util/TreeMap.html

обратите внимание, что порядок поддерживается отсортированной картой (будь то явная компаратор предоставляется) должен быть согласован с equals, если эта отсортированная карта должна правильно реализовать интерфейс карты. (См. Comparable или Comparator для точного определения согласованного с равными.) Это так, потому что интерфейс карты определяется в терминах операции equals, но карта выполняет все ключевые сравнения, используя свой метод compareTo (или compare), поэтому два ключа, которые считаются равными этим методом, с точки зрения отсортированной карты равны. Поведение отсортированной карты четко определенный, даже если его порядок несовместим с equals; он просто не подчиняется общему контракту интерфейса карты.

Это, наверное, не то, что вы хотите.

Если карта сравнительно мала, и вам не нужно извлекать отсортированные записи очень много раз, решение состоит в том, чтобы использовать HashMap (или TreeMap без явного задания компаратора) и сортировать записи без учета регистра, когда вам нужно их упорядочить.


для этого вам придется использовать две отдельные карты деревьев с одинаковым содержимым, но разными компараторами.


может быть, это сделает работу:

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

вам понадобится multimap: каждая запись этого multimap сохраняет регистр ключи и aanother карта с оригинальными ключами в качестве значения.

есть много свободно используемых реализаций multimaps, таких как Общих Собраний, Google Коллекции, etc


в дополнение ко всем другим ответам и соглашаясь, что невозможно иметь одну структуру TreeMap с разными компараторами:

из вашего вопроса я понимаю, что у вас есть два требования: модель данных должна быть чувствительной к регистру (вы хотите, чтобы значения с учетом регистра при использовании get()), ведущий должен быть нечувствительным к регистру (вы хотите, чтобы порядок с учетом регистра, презентация - это просто предположение).

предположим, мы заполняем карту сопоставления (АА,obj1), (АА,obj2), (АА,obj3), (АА,obj4). Итератор будет предоставлять значения в порядке: (obj4, obj3, obj2, obj1)(*). Теперь, какой порядок вы ожидаете, если карта была заказана без учета регистра? Все четыре ключа будут равны, а порядок не определен. Или вы ищете решение, которое разрешило бы коллекцию {obj1, obj2, obj3, obj4} для ключа "AA"? Но это другой подход.

поэтому призывает сообщество быть честным: поэтому мой совет в этом точка, чтобы посмотреть на ваше требование снова:)

(*) не проверено, предполагается, что 'A'


использовать floorEntry а то higherEntry в цикле, чтобы найти записи без учета регистра; остановитесь, когда найдете точное совпадение ключей.