我需要一组有序的对象,目前正在使用TreeSet
。我的问题是对象的compareTo
通常会返回0
,这意味着这两个对象的顺序保持不变。 TreeMap
(默认情况下由TreeSet
使用)会将它们视为同一个对象,但这不是真的。
我可以使用TreeMap
的替代方案吗?
用例:我有一组可显示的对象。我想按Y坐标对它们进行排序,以便它们以正确的顺序呈现。当然,两个对象可能具有相同的Y坐标。
答案 0 :(得分:9)
您要定义一个要比较的条件,但您需要添加额外的条件。
你说:
我有一组可显示的对象。我想按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
。如果其中一个属性与其他属性相同,则可能不应移动它们。如果有其他属性要比较使用它。
答案 1 :(得分:4)
您遇到的问题是compareTo
返回0
表示对象相同。与此同时,您将它们放入一个集合中,该集合不允许多个相等元素的副本。
重写你的compareTo
,以便不相等的元素返回不同的值,或使用类似java.util.PriorityQueue
的内容,允许多个相等元素的副本。
答案 2 :(得分:1)
我以前做过这个。它是一个有序的多映射,它只是List对象的TreeMap。像这样......
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]}
答案 3 :(得分:0)
我对自己有一个想法,但它更像是一种解决方法
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.
}
答案 4 :(得分:0)
使用有序集(例如TreeSet)时,要记住两件重要的事情:
1)他们是集合;同一集合中不允许使用两个相等的元素
2)平等必须与比较机制(比较器或可比较的)一致
因此,在您的情况下,您应该通过添加一些二级排序标准来“打破关系”。例如:首先使用Y轴,然后使用X,然后使用一些唯一的对象标识符。