TreeMap странно работает

У меня есть HashMap, соответствующий строке с двойным значением, и я пытаюсь отсортировать его по значениям с помощью TreeMap после некоторых изменений этих значений.

Это работает, и я могу распечатать все дерево, но когда я пытаюсь получить доступ к определенному значению по его ключу, оно возвращает null примерно в половине случаев, всегда на одних и тех же ключах, даже если их значения не отличаются от других. Аналогично, повторная попытка удалить ключ не работает.

Вот пример моей проблемы. На самом деле это не часть моего кода, но воспроизводит ту же проблему:

    Map<String, Double> freq = new HashMap<String, Double>();
    ValueComparator classif = new ValueComparator(freq);
    TreeMap<String, Double> sorted_freq = new TreeMap<String, Double>(classif);

    freq.put("bara" , 0.1142204454597373);
    freq.put("religieux" , 0.05711022272986865);
    freq.put("alliance" , 0.05711022272986865);
    freq.put("ethnique" , 0.05711022272986865);
    freq.put("officiers" , 0.1142204454597373);
    freq.put("ascendants" , 0.05711022272986865);
    freq.put("correspondait" , 0.05711022272986865);
    freq.put("toko" , 0.05711022272986865);
    freq.put("evenement" , 0.1142204454597373);
    freq.put("certainement" , 0.05711022272986865);
    freq.put("chance" , 0.05711022272986865);

    sorted_freq.putAll(freq);
    for(String key:freq.keySet()){
        System.out.println(key+" : "+freq.get(key));
    }
    System.out.println("------------------------------------------------------------------");
    for(String key:sorted_freq.keySet()){
        System.out.println(key+" : "+sorted_freq.get(key));
    }

Вот компаратор, который я использую для построения TreeMap:

 class ValueComparator implements Comparator<String> {

    Map<String, Double> base;
    public ValueComparator(Map<String, Double> freq) {
        this.base = freq;
    }

    public int compare(String a, String b) {
        if (base.get(a) > base.get(b)) {
            return -1;
        }else if(base.get(a)==base.get(b)){
            return 0;
        } else {
            return 1;
        } 
    }
}

Если у вас есть понимание этого, пожалуйста, просветите меня.


person Laetan    schedule 25.06.2014    source источник
comment
Какие модификации? Если этот компаратор станет непоследовательным или неполным, TreeMap перестанет работать.   -  person Thilo    schedule 25.06.2014
comment
Я попробовал метод equals и примерно половина записей просто исчезла... Модификации заключаются только в делении значений на целое число. Значения, которые я взял в примере, являются результатом этой модификации.   -  person Laetan    schedule 25.06.2014


Ответы (3)


Ваша проблема в том, что если две записи вашей исходной карты имеют одинаковое значение, то останется только последняя вставленная в freq. Поэтому ключ, который был заменен в freq, удаляется из карты дерева.

Пример:

freq.put("bara" , 0.1142204454597373);
freq.put("religieux" , 0.05711022272986865);
freq.put("alliance" , 0.05711022272986865);

затем freq.get("religieux") возвращает null, потому что, поскольку оно имеет то же значение, что и "alliance", а "alliance" было вставлено позже, "religieux" было заменено на "alliance", поскольку компаратор считает их равными.

Кроме того, как предлагается в других ответах, вам нужно сравнить значения Double, выполняя base.get(a).equals(base.get(b))

person Jean Logeart    schedule 25.06.2014
comment
+1 Чтобы решить эту проблему, вы также можете сравнить ключи, если значения равны (измените return 0 на return a.compareTo(b)) - person Thilo; 25.06.2014
comment
Большое спасибо, ваши решения, кажется, исправляют мою проблему. Я ничего не знаю об использовании класса Comparator, так что это действительно помогает - person Laetan; 25.06.2014
comment
Это может не решить основную проблему вашего метода сравнения. Вместо использования == вы должны использовать equals в методе сравнения. - person vinayknl; 25.06.2014

if(base.get(a)==base.get(b))

Это сравнивает экземпляры объектов Double вместо значений. Попробуйте изменить его на

if(base.get(a).doubleValue()==base.get(b).doubleValue())
person Jack    schedule 25.06.2014

Измените метод сравнения, как показано ниже.

public int compare(String a, String b) {
    if (base.get(a) > base.get(b)) {
        return -1;
    }else if(base.get(a).equals(base.get(b))){
        return 0;
    } else {
        return 1;
    } 
}

это основная причина сбоя вашего кода

person vinayknl    schedule 25.06.2014
comment
Это просто заставляет большинство записей исчезнуть. - person Laetan; 25.06.2014
comment
Ваша реализация компаратора говорит, что имеет только не повторяющиеся значения. это причина того, что в записях отсутствуют повторяющиеся значения, поскольку он возвращает 0 при добавлении записей из хэш-карты в древовидную карту. - person vinayknl; 25.06.2014
comment
Хорошо. Я только что скопировал реализацию компаратора. Я почти ничего не знаю об этом классе. Может быть, мне следует узнать немного больше о том, что я использую: p - person Laetan; 25.06.2014