Сравните HashMap с объектами - PullRequest
       2

Сравните HashMap с объектами

1 голос
/ 16 декабря 2011

У меня есть hashmap<CustomObject,Integer>, и я хотел бы сравнить целые числа (значения) в каждой записи. Итак, я бы хотел отсортировать мои значения по их Integer значению в порядке убывания. У меня есть Comparator, который состоит из следующего ...

class Compare implements Comparator<Integer>{
    Map<CustomObject,Integer> map;
    /**
     * Constructs our map
     * @param map map to be sorted.
     */
    public Compare(Map<CustomObject,Integer> map){
        this.map = map;
    }
    /**
     * Performs the comparison between two entries.
     */
    public int compare(Integer one, Integer two){
        if(map.get(one) <= map.get(two)){
            return 1;
        }else{
            return 0;
        }
    }
}

Я передаю свой Hashmap в TreeMap, вызывая следующую строку кода .. Tmap.putAll(Hmap);. Где Tmap и Hmap определены как:

private HashMap<CustomObject,Integer> Hmap;
private TreeMap<CustomObject,Integer> Tmap;

Когда я запускаю свой код, я получаю ошибку Exception in thread "main" java.lang.ClassCastException: CustomObject cannot be cast to java.lang.Comparable.

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

TreeMap<CustomObject,Integer> sorted = Tmap.putAll(hmap);
sorted.get(o);

, где o - это CustomObject.

Я думаю, что неправильно понял, как работает компаратор .. что я делаю не так? Как бы я сравнил два целочисленных значения?

EDIT

Просто чтобы уточнить, что я на самом деле пытаюсь сделать ...

Я хочу сравнить целые числа, которые связаны с CustomObject. Я не могу сделать ключ Integer, потому что эти Integer могут быть не уникальными. Я должен был сравнить их, потому что я хотел бы отсортировать мою коллекцию в порядке убывания на основе их значения Integer.

Ответы [ 6 ]

5 голосов
/ 16 декабря 2011

Вам нужно изменить компаратор для сравнения CustomObject s, а не Integers:

class Compare implements Comparator<CustomObject>{
    Map<CustomObject,Integer> map;
    /**
     * Constructs our map
     * @param map map to be sorted.
     */
    public Compare(Map<CustomObject,Integer> map){
        this.map = map;
    }
    /**
     * Performs the comparison between two entries.
     */
    public int compare(CustomObject left, CustomObject right){
        return map.get(left).compareTo(map.get(right));
    }
}

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

private Map<CustomObject,Integer> Tmap = 
    new TreeMap<CustomObject,Integer>(new Compare(HMap));
1 голос
/ 16 декабря 2011

Я бы предложил использовать мультикарту, проиндексированную целым числом. Если вам нужно сохранить возможность поиска этих пар по объектам, вы можете сохранить обе карты. Java не поставляется с мультикартой, но есть простые решения. Здесь является примером Map<Integer,List<Object>> (прокрутите вниз до раздела мультикарты).

1 голос
/ 16 декабря 2011

Я думаю, что проблема будет в том, что вы используете неправильный TreeMap конструктор. Тот, который вы используете, требует, чтобы все ключи были экземплярами классов, которые реализуют Comparable. Ваш CustomObject нет. Вы должны использовать конструктор, который принимает параметр Comparator; например,

TreeMap<CustomObject,Integer> tmap = 
    new TreeMap<CustomObject,Integer>(new Compare());

Это также скажет вам, что ваш класс Compare должен реализовывать Comparator<CustomObject>, а не Comparator<Integer>.

Другая проблема заключается в том, что ваш компаратор не реализует правильную семантику. Метод сравнения должен возвращать число -ve, если arg1 arg2; например,

public int compare(CustomObject one, CustomObject two){
    return Integer.compare(map.get(one), map.get(two));
}

И даже это изворотливо:

  • Если любые два экземпляра CustomObject, которые отображаются в одно и то же целое число, будут рассматриваться как равные, и вы не сможете использовать оба в качестве (различных) ключа в TreeMap.

  • Ваш компаратор бросит NPE, если в map нет записи для one или two.

1 голос
/ 16 декабря 2011

У этого подхода есть несколько проблем.

  • TreeMap игнорирует дубликаты (когда CompareTo возвращает 0) В вашем случае он будет только добавлять убывающие целочисленные значения.Вы можете исправить это так, что числа могут быть в любом порядке, но при этом все записи с дублирующимися значениями будут отброшены.
  • Поля, используемые в compareTo, не могут измениться или повредят коллекцию.1008 * Вам нужно знать весь ключ, чтобы найти значение.В этом случае вам нужно знать значение в этом случае, чтобы найти его, что может быть не очень полезно.

Вам лучше создать List<Entry<CustomObject,Integer>> из map.entrySet(), который вы можетесортировать, так как это позволяет дублировать и упорядочено.

1 голос
/ 16 декабря 2011
new TreeMap<..>(new Compare<..>(map))

Вы должны указать компаратор при построении дерева. В противном случае предполагается, что ваши ключи сравнимы (а они нет)

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

0 голосов
/ 16 декабря 2011

Сначала необходимо указать, что ключ должен быть Integer, а значение должно быть CustomObject, а затем HashMap может быть отсортирован на основе компаратора. Но по умолчанию HashMap или, если вы хотите сортировать по CustomObject, то вы должны сделать CustomObject реализующим Comparable и написать метод сравнения в том, который заставит HashMap сортировать на основе CustomObject. Если вы поняли это. и хочу попробовать себя. или если вы хотите, чтобы я объяснил примером, я могу это сделать.

Вопрос сбивает с толку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...