2014-09-03 4 views
2

У меня есть карта, как так:Сортировать карту на основе размера

Map<List<Item>, Double> items = new HashMap<List<Item>, Double>(); 

Я хотел бы разобраться в этом HashMap на основе размера List<Item>, где самые крупные из них размера, в первую очередь. Тем не менее, я не забочусь о заказе внутри объектов с одинаковым размером.

До сих пор я пытался использовать TreeSet так:

SortedSet<Map.Entry<List<Item>, Double>> sortedItems = new TreeSet<Map.Entry<List<Item>, Double>>(
    new Comparator<Map.Entry<List<Item>, Double>>() { 

     @Override 
     public int compare(
      Entry<List<Item>, Double> o1, 
      Entry<List<Item>, Double> o2) { 
       return o2.getKey().size() - o1.getKey().size(); 
     } 
    }); 
sortedItems.addAll(items.entrySet()); 

Однако sortedItems объект занимает лишь один из каждого размера списка. Он обрабатывает списки одинакового размера как дубликаты и игнорирует их. Как я могу исправить эту проблему.

EDIT: Итак, из того, что я могу сказать, когда сравниваются 2 списка одного и того же размера, мой метод compare возвращает 0. Это говорит множеству, что записи равны, и они рассматриваются как дубликаты. Поэтому я предполагаю, что единственный способ исправить это - убедиться, что метод сравнения никогда не возвращает 0. Так что я написал этот код:

@Override 
public int compare(
    Entry<List<AuctionItem>, Double> o1, 
    Entry<List<AuctionItem>, Double> o2) { 
     if (o1.getKey().size() <= o2.getKey().size()) { 
      return -1; 
     } else { 
      return 1; 
     } 
} 
+1

Затем ваш компаратор не должен возвращать 0. Возврат 0 означает, что «эти элементы одинаковы», и вы не можете иметь одинаковые элементы на карте. – immibis

+0

@immibis Итак, что я должен вернуть? Может ли это быть чем-то другим, кроме 0 или имеет значение, верну я положительное или отрицательное число? – Ogen

+0

Вам нужно решить, как их сортировать. – immibis

ответ

1

Если вы попытаетесь поместить элемент в TreeSet, для которого пользовательский Comparator возвращает 0, элемент не быть помещен в Set.

Вы должны использовать Comparator, который не возвращает 0. Для List s, размеры которых равны, вы должны определить согласованный, произвольный заказ.

Вот простой и удобный способ сделать это:

new Comparator<Map.Entry<List<Item>, Double>>() { 
    @Override 
    public int compare(Entry<List<Item>, Double> o1, 
         Entry<List<Item>, Double> o2) { 

     int diff = o2.getKey().size() - o1.getKey().size(); 
     return diff != 0 ? diff : 
      System.identityHashCode(o2.getKey()) - 
       System.identityHashCode(o1.getKey()); 
    } 
}; 

В основном то, что я делаю это: если 2 списки имеют разный размер, size2 - size1 будет делать. Если они имеют одинаковый размер, я возвращаю разницу их хэш-кодов , которые всегда будут отличаться от 0, потому что идентификатор hashcode - это адрес памяти, который отличается для разных объектов. И это всегда одно и то же для объекта, поэтому компаратор всегда будет возвращать тот же порядок для 2 списков с одинаковым размером.

Используя этот компаратор, вы получите отсортированный набор, который позволяет спискам иметь одинаковый размер, и он будет отсортирован по размеру списка.

3

Вы используете TreeSet с Comparator, и в соответствии с вашей реализацией compare(), она возвращает 0, если размер списка такой же. Поскольку TreeSet не может содержать дубликаты, он добавляет только один из тех списков, размер которых равен. Вам не нужно создавать TreeSet, чтобы отсортировать ваш Map, потому что SETS следует использовать, когда элементы напоминают математические множества (без дубликатов элементов). Вы можете сделать:

List<Map.Entry<List<Item>, Double>> list = 
     new LinkedList<Map.Entry<List<Item>, Double>>(map.entrySet()); 

Collections.sort(list, new Comparator<Map.Entry<List<Item>, Double>>() 
     { 
      public int compare(Map.Entry<List<Item>, Double> o1, Map.Entry<List<Item>, Double> o2) 
      { 
       return (o1.getKey().size().compareTo(o2.getKey.size()); 
      } 
     }); 

То есть, введите данные карты в список, а затем отсортируйте список.

+0

Нет, просто нет. Вы не можете сортировать карту. Карта не имеет порядка. Вам нужно поместить записи в список, чтобы иметь возможность сортировать их. –

+0

@ ChristofferHammarström мой плохой, спасибо, отредактировал его. –

1

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

В основе любая Карта не упорядоченная коллекция. Короче говоря, если «Пит» имеет высоту 67 дюймов, а «Боб» имеет высоту 72 дюйма, то без какого-либо дополнительного бита информации невозможно определить, должен ли Боб прибыть до или после Пита.

Упорядоченный «ключ» или, в данном случае, «имя», можно наложить алфавитный заказ, и в этом случае «Боб» доходит до «Пит».

Упорядоченный по значению или в этом случае «высота» может налагать наименьший по величине порядок, и в этом случае «Пит» приходит перед «Боб».

Я уверен, что вы знаете, что хотите заказать (размер списка), но этот пример означает иллюстрацию того, что только карта является плохой структурой данных для заказа. Даже упорядоченные карты в Java сортируются только по порядку вставки.

Мое предложение состоит в том, чтобы сохранить две коллекции в одном классе упаковки. Тот, который содержит упорядоченный список ключей, и другой, который содержит карту. Пройдите упорядоченный список ключей и верните значения карты в этом порядке, если вы хотите упорядоченный набор значений по их ключевым характеристикам. Это будет понятнее и понятнее.

Также понимайте, что Карта не слушает ключевые значения, поэтому, если кто-то, у кого есть ключ, решает добавить запись в Список, которую поддерживает ключ, Карта не будет знать об изменениях и не будет пересчитайте ведро для прежнего значения ключа. Таким образом, чтобы правильно использовать карту, вам нужно подойти к ней одним из двух способов.

  1. Сделать ключи карты неизменными, скопировать значения на входе и вернуть Collections.unmodifiableList(...) обертки на выходе.
  2. Принять ключи карты, которые можно прослушать, и сделать карту подписчика на обновления ключей, которые могут возникнуть. Когда карта обнаруживает изменение ключа, значения удаляются из старого местоположения ключа и снова добавляются обратно к карте с помощью нового ключа.
0

Если вы не нуждаются в постоянной сортировкой с течением времени, вы можете сделать это:

Map<List<Item>, Double> items = new HashMap<>(); 

List<Map.Entry<List<Item>, Double>> list = new ArrayList<>(items.entrySet()); 
Collections.sort(list, new Comparator<Map.Entry<List<Item>, Double>>() { 
     @Override 
     public int compare(
      Map.Entry<List<Item>, Double> o1, 
      Map.Entry<List<Item>, Double> o2) { 
      return Integer.compare(o2.getKey().size(), o1.getKey().size()); 
     } 
    } 

}); 

Если вам нужен TreeSet или TreeMap, то использование Comparator это хорошо, но у вас есть для определения того, что происходит, когда размер списков равен: вам нужно использовать другие критерии для определения порядка (например, сравнение каждого элемента a, b обоих списков до a.compareTo(b) != 0).

Смежные вопросы