CompareTo может вернуть 0, альтернатива TreeSet / TreeMap - PullRequest
6 голосов
/ 15 июня 2010

Мне нужен отсортированный набор объектов, и в настоящее время я использую TreeSet. Моя проблема в том, что compareTo объектов будет часто возвращать 0, что означает, что порядок этих двух объектов следует оставить без изменений. TreeMap (используется TreeSet по умолчанию) будет рассматривать их как один и тот же объект, что не соответствует действительности.

Какую альтернативу TreeMap я могу использовать?


Вариант использования: у меня есть набор отображаемых объектов. Я хочу отсортировать их по координате Y, чтобы они отображались в правильном порядке. Конечно, два объекта могут иметь одинаковую координату Y.

Ответы [ 5 ]

9 голосов
/ 15 июня 2010

Вы определяете один критерий для сравнения, но нужно добавить дополнительные критерии.

Вы говорите:

У меня есть набор отображаемых объектов.Я хочу отсортировать их по координате Y, чтобы они отображались в правильном порядке.Конечно, два объекта могут иметь одинаковую координату Y.

Итак, если два элемента имеют одинаковую координату Y, что вы ставите первым?Каковы будут другие критерии?

Это может быть время создания, это может быть координата x, вам просто нужно определить это:

Map<String,Thing> map = new TreeMap<String,Thing>(new Comparator<Thing>(){
     public int compare( Thing one, Thing two ) {
         int result = one.y - two.y;
         if( result == 0 ) { // same y coordinate use another criteria
             result = one.x - two.x;
             if( result == 0 ) { //still the same? Try another criteria ( maybe creation time
                 return one.creationTime - two.creationTime
             }
          }
          return result;
     }
});

Вы должны определить, когда один Thing выше / ниже /равно / чем другие Thing.Если один из атрибутов совпадает с другим, вероятно, вам не следует их перемещать.Если есть другой атрибут для сравнения, используйте его.

4 голосов
/ 15 июня 2010

Проблема, с которой вы сталкиваетесь, заключается в том, что compareTo, возвращающий 0, означает, что объекты равны. В то же время вы помещаете их в набор, который не позволяет создавать несколько копий одинаковых элементов.

Либо переписайте свой compareTo, чтобы неравные элементы возвращали разные значения, либо используйте что-то вроде java.util.PriorityQueue, которое допускает несколько копий одинаковых элементов.

1 голос
/ 15 июня 2010

Я делал это раньше.Это упорядоченная мульти-карта, и это просто TreeMap объектов List.Как это ..

Map<KeyType, List<ValueType>> mmap = new TreeMap<KeyType, List<ValueType>>();

Вам нужно создавать новый LinkedList каждый раз, когда вводится новый ключ, поэтому может быть полезно обернуть его в пользовательский класс контейнера.Я попытаюсь что-то найти.


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

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class MTreeMap<K, V> {

   private final Map<K, List<V>> mmap = new TreeMap<K, List<V>>();
   private int size = 0;

   public MTreeMap() {
   }

   public void clear() {
      mmap.clear();
      size=0;
   }

   public boolean containsKey(K key) {
      return mmap.containsKey(key);
   }

   public List<V> get(K key) {
      return mmap.get(key);
   }

   public boolean isEmpty() {
      return mmap.isEmpty();
   }

   public Set<K> keySet() {
      return mmap.keySet();
   }

   public Collection<List<V>> valueLists() {
      return mmap.values();
   }

   public void put(K key, V value) {

      List<V> vlist = mmap.get(key);
      if (null==vlist) {
         vlist = new LinkedList<V>();
         mmap.put(key, vlist);
      }
      vlist.add(value);
      ++size;
   }

   public List<V> remove(Object key) {
      List<V> vlist = mmap.remove(key);

      if (null!=vlist) { 
         size = size - vlist.size() ;
      }
      return vlist;
   }

   public int size() {
      return size;
   }

   public String toString() {
      return mmap.toString();
   }

}

Вот элементарный тест:

public class TestAnything {

   public static void main(String[] args) {

      MTreeMap<Integer, String> mmap  = new MTreeMap<Integer, String>();

      mmap.put(1, "Value1");
      mmap.put(2, "Value2");
      mmap.put(3, "Value3");
      mmap.put(1, "Value4");
      mmap.put(3, "Value5");
      mmap.put(2, "Value6");
      mmap.put(2, "Value7");

      System.out.println("size (1) = " + mmap.get(1).size());
      System.out.println("size (2) = " + mmap.get(2).size());
      System.out.println("size (3) = " + mmap.get(3).size());
      System.out.println("Total size = " + mmap.size());

      System.out.println(mmap);
   }

}

Вывод такой:

size (1) = 2
size (2) = 3
size (3) = 2
Total size = 7
{1=[Value1, Value4], 2=[Value2, Value6, Value7], 3=[Value3, Value5]}
0 голосов
/ 15 июня 2010

При использовании отсортированных наборов следует помнить 2 важные вещи (например, TreeSet):

1) Это наборы;два одинаковых элемента недопустимы в одной коллекции

2) Равенство должно соответствовать механизму сравнения (компаратора или сопоставимого)

Следовательно, в вашем случае вы должны "разорвать связи"добавив некоторые вторичные критерии заказа.Например: сначала используйте ось Y, затем X, а затем какой-то уникальный идентификатор объекта.

См. Также http://eyalsch.wordpress.com/2009/11/23/comparators/

0 голосов
/ 15 июня 2010

У меня есть одна идея, но это скорее обходной путь

int compare(Object a, Object b) {
   an = a.seq + (a.sortkey << 16); // allowing for 65k items in the set
   bn = b.seq + (a.sortKey << 16);
   return an - bn; // can never remember whether it's supposed to be this or b - a.
}
  • sortKey = что действительно важно для сортировки, например, координата Y
  • seq= порядковый номер, назначенный объектам при добавлении в набор
...