我希望将对象列表排序为属性' sort_1'。但是,当我想要删除时,我希望使用“属性”#id;'。以下代码表示问题。
package javaapplication1;
import java.util.TreeSet;
public class MyObj implements Comparable<MyObj> {
public long sort_1;
public long id;
public MyObj(long sort, long id) {
this.sort_1=sort;
this.id=id;
}
@Override
public int compareTo(MyObj other) {
int ret = Long.compare(sort_1, other.sort_1);
return ret;
}
public String toString() {
return id+":"+sort_1;
}
public static void main(String[] args) {
TreeSet<MyObj> lst=new TreeSet<MyObj>();
MyObj o1 = new MyObj(99,1);
MyObj o2 = new MyObj(11,9);
lst.add(o1);
lst.add(o2);
System.out.println(lst);
MyObj o3 = new MyObj(1234, 1);
//remove myObje with id 1
boolean remove=lst.remove(o3);
System.out.println(lst);
}
}
此代码的输出为:
[9:11, 1:99]
[9:11, 1:99]
我需要对列表进行排序,因为我对列表进行了大量添加。我不想明确使用任何&#39;排序&#39;方法。我有什么选择?
编辑:
我的要求是:拥有&#39; id&#39;虽然很独特,但可能存在重复的对象&#39; sort&#39;值。
答案 0 :(得分:3)
我偶然发现了昨天的情况。这似乎是TreeMap实现的工件(TreeSet用来存储其条目)。
TreeMap使用二叉搜索树来存储键/值对,但它只使用给定的Comparator(或者如果键类实现Comparable,则使用compare函数)来检查是否相等,正如您在此代码中所看到的exxcerpt :
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
我几乎称之为(不是真正可修复的)错误,因为JavaDoc of the Comparable interface明确表示使用compareTo函数返回0并不一定意味着&#34;相等&#34;:
强烈建议,但并非严格要求(x.compareTo(y)== 0)==(x.equals(y))。
您无法以您希望的方式在TreeSet中存储内容。我建议您使用普通HashMap或LinkedHashMap,然后在需要使用Collections.sort对其进行排序时对输出进行排序。
除此之外,我总是觉得实现Comparable接口很奇怪。大多数事情都不是真的有自然的&#34;订购很明显。有时候这会导致奇怪的错误(比如这个!),所以我通常只在需要使用自定义比较器时才进行排序。 Java 8也使编写它们变得非常简单!
答案 1 :(得分:0)
使用Map<Long,MyObject> objectsByIDs;
按ID:objectsByIDs.put(id,myObjectInstance);
存储数据对象。然后,您可以通过这种方式从地图中检索它们MyObject o = objectsByIDs.get(id);
并将其从两个地方删除:objectsByIDs.remove(o); lst.remove(o)
。
答案 2 :(得分:0)
Thread [main] (Suspended (breakpoint at line 18 in MyObj))
MyObj.compareTo(MyObj) line: 18
MyObj.compareTo(Object) line: 1
TreeMap<K,V>.getEntry(Object) line: not available
TreeMap<K,V>.remove(Object) line: not available
TreeSet<E>.remove(Object) line: not available
MyObj.main(String[]) line: 45
即使使用Comparator也不起作用。在我看来,像Sun / Oracle / openJDK的一些聪明的开发人员认为做compareTo()== 0和equals()相同。它不是。
您唯一的选择是使用外部数据结构来检查建议的相等性,或者自己循环,找到您想要的项目,然后将其删除。
编辑: 现在我懂了。他们使用二分搜索搜索项目,这就是他们做compareTo()的原因。
答案 3 :(得分:0)
我认为你遇到的问题是你正在实现Comparable,但是你的实现似乎与equals不一致 - 并且你没有实现任何相等的方法。那就是:
当且仅当e1.compareTo(e2)== 0与c1的每个e1和e2的e1.equals(e2)具有相同的布尔值时,C类的自然排序被认为与equals一致。
在您的情况下,当您构建这三个对象时:
MyObj o1 = new MyObj(99,1);
MyObj o2 = new MyObj(11,9);
MyObj o3 = new MyObj(1234, 1);
你会看到o1.compareTo(o3)== -1,而o1.equals(o3)== false。
但你似乎想要o1.equals(o3)== true。
此外,如果对象已存在于集合中,则认识到TreeSet.add()返回false。此检查基于equals()方法。
要解决此问题,请覆盖Object.equals()和Object.hashCode(),以便它们考虑MyObj.id字段,并在compareTo()方法不相等时继续使用sort_1字段。
package javaapplication1;
import java.util.TreeSet;
public class MyObj implements Comparable<MyObj> {
public long sort_1;
public long id;
public MyObj(long sort, long id) {
this.sort_1 = sort;
this.id = id;
}
@Override
public int compareTo(MyObj other) {
return (this.equals(other))? 0 : Long.compare(sort_1, other.sort_1);
}
@Override
public boolean equals(Object obj) {
MyObj other = (MyObj) obj;
return this.id == other.id && this.sort_1 == other.sort_1;
}
@Override
public int hashCode() {
return (int) id;
}
public String toString() {
return id + ":" + sort_1;
}
public static void main(String[] args) {
TreeSet<MyObj> lst = new TreeSet<MyObj>();
MyObj o1 = new MyObj(99L, 1L);
MyObj o2 = new MyObj(11L, 9L);
MyObj o3 = new MyObj(1234L, 1L);
MyObj o4 = new MyObj(1234L, 1L);
System.out.println( "Adding o1: " + lst.add(o1));
System.out.println( "Adding o2: " + lst.add(o2));
System.out.println( "Adding o3: " + lst.add(o3));
System.out.println( "Adding o4: " + lst.add(o4));
System.out.println(lst);
System.out.println("o1.compareTo(o3) : " + o1.compareTo(o3));
System.out.println("o1.equals(o3) : " + o1.equals(o3));
//remove myObje with id 1
boolean remove = lst.remove(o3);
System.out.println(lst);
}
}
输出:
Adding o1: true
Adding o2: true
Adding o3: true
Adding o4: false
[9:11, 1:99, 1:1234]
o1.compareTo(o3) : -1
o1.equals(o3) : false
[9:11, 1:99]
答案 4 :(得分:0)
remove
具有不同的逻辑并且在TreeSet
中进行排序几乎肯定是不可能的,即使有可能,如果你看起来很有趣也会破坏它。 不要那样做。
试图搞砸比较器所以它做了一些神奇的事情是一个可怕的想法。接受TreeSet
会关注的只有一个比较概念。你想用另一个比较概念做的事情不应该使用TreeSet
方法来做到这一点。
您可以做的是使用特殊的removeId(int)
方法来执行类似
void removeId(int id) {
Iterator<MyObj> itr = set.iterator();
while (itr.hasNext()) {
if (itr.next().id == id) {
itr.remove();
break;
}
}
}