CompareTo может возвратиться 0, альтернатива TreeSet/TreeMap

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

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


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

6
задан Bart van Heukelom 14 June 2010 в 21:04
поделиться

5 ответов

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

Вы говорите:

У меня есть набор отображаемых объектов. Я хочу отсортировать их по координате 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;
     }
});

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

9
ответ дан 8 December 2019 в 17:18
поделиться

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

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

4
ответ дан 8 December 2019 в 17:18
поделиться

Я уже делал это раньше. Это упорядоченный мультимап, и он представляет собой просто 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]}
1
ответ дан 8 December 2019 в 17:18
поделиться

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

1) Это множества; два одинаковых элемента не могут находиться в одной коллекции

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

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

See also http://eyalsch.wordpress.com/2009/11/23/comparators/

0
ответ дан 8 December 2019 в 17:18
поделиться

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

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 = порядковый номер, присваиваемый объектам при добавлении в набор
0
ответ дан 8 December 2019 в 17:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: