如何按可以重复的值对 sortedset 进行排序?
How to sort sortedset by value that can be duplicate?
在 Java 1.7 中,我有一个“Post class”,它具有 Post ID 和每个 Post 的投票数。我想创建可以始终按投票数排序的 Post 的排序集。请注意,不同的 Post 可以有相同的票数。
问题是,当我创建具有 2 个不同 ID 和不同票数的 2 个不同 Post 时,排序集检测到它们是不同的 Post,因此将它们添加两次用新投票数替换现有线程。下面的例子
Post Class:
public class Post implements Comparable<Post> {
protected int id;
protected int votes;
public Post(int id) {
this.id = id;
this.votes = 0;
}
public Post(int id, int votes) {
this.id = id;
this.votes = votes;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
Post post= (Post) o;
return id == employee.id;
}
@Override
public int hashCode() {
return Objects.hash(this.id);
}
@Override
public int compareTo(Post t) {
int diff = ((Integer) t.votes).compareTo(this.votes);
if (diff == 0) {
return ((Integer) t.id).compareTo(this.id);
}
return diff;
}
}
运行方法:
public void run() {
SortedSet<Post> set = new TreeSet<Post>();
Post t1 = new Post(1, 30);
Post t2 = new Post(1, 40);
Post t3 = new Post(2, 100);
set.add(t1);
set.add(t2);
set.add(t3);
for (Post t : set) {
System.err.println(t.id + " >> " + t.votes);
}
}
预期输出:
2 >> 100
1 >> 40
实际输出
2 >> 100
1 >> 40
1 >> 30
如您所见,问题是相同的 Post 在集合中出现了两次,这不是所需的输出。
我也尝试避免使用 Comparable 接口,而是使用 Comparator,但是,我得到了相同的结果。
比较器Class:
class CompareByVotes implements Comparator<Post> {
@Override
public int compare(Post t1, Post t2) {
int diff = ((Integer) t2.votes).compareTo(t1.votes);
if (diff == 0) {
return ((Integer) t2.id).compareTo(t1.id);
}
return diff;
}
}
问题:
是否需要进行任何更改才能使其按预期工作?
当您根据 equals()
方法比较的对象相等时,您的 compareTo()
方法不会 return 0
。但是,这是 SortedSet
接口所要求的:
Note that the ordering maintained by a sorted set (whether or not an explicit comparator is provided) must be consistent with equals if the sorted set is to correctly implement the Set
interface. (See the Comparable
interface or Comparator
interface for a precise definition of consistent with equals.) This is so because the Set
interface is defined in terms of the equals operation, but a sorted set performs all element comparisons using its compareTo
(or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the sorted set, equal. The behavior of a sorted set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set
interface.
因此当它们相等时,您的 compareTo()
方法必须 return 0
。一种可能的解决方案是这样的:
public int compareTo(Post t) {
if (equals(t)) {
return 0;
}
int diff = ((Integer) t.votes).compareTo(this.votes);
if (diff == 0) {
return ((Integer) t.id).compareTo(this.id);
}
return diff;
}
此外,请记住 add()
不会“覆盖”对象,当集合中已经存在相同的对象时。请参阅 add()
的文档:
[...] If this set already contains the element, the call leaves the set unchanged and returns false.
在 Java 1.7 中,我有一个“Post class”,它具有 Post ID 和每个 Post 的投票数。我想创建可以始终按投票数排序的 Post 的排序集。请注意,不同的 Post 可以有相同的票数。
问题是,当我创建具有 2 个不同 ID 和不同票数的 2 个不同 Post 时,排序集检测到它们是不同的 Post,因此将它们添加两次用新投票数替换现有线程。下面的例子
Post Class:
public class Post implements Comparable<Post> {
protected int id;
protected int votes;
public Post(int id) {
this.id = id;
this.votes = 0;
}
public Post(int id, int votes) {
this.id = id;
this.votes = votes;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
Post post= (Post) o;
return id == employee.id;
}
@Override
public int hashCode() {
return Objects.hash(this.id);
}
@Override
public int compareTo(Post t) {
int diff = ((Integer) t.votes).compareTo(this.votes);
if (diff == 0) {
return ((Integer) t.id).compareTo(this.id);
}
return diff;
}
}
运行方法:
public void run() {
SortedSet<Post> set = new TreeSet<Post>();
Post t1 = new Post(1, 30);
Post t2 = new Post(1, 40);
Post t3 = new Post(2, 100);
set.add(t1);
set.add(t2);
set.add(t3);
for (Post t : set) {
System.err.println(t.id + " >> " + t.votes);
}
}
预期输出:
2 >> 100
1 >> 40
实际输出
2 >> 100
1 >> 40
1 >> 30
如您所见,问题是相同的 Post 在集合中出现了两次,这不是所需的输出。
我也尝试避免使用 Comparable 接口,而是使用 Comparator,但是,我得到了相同的结果。
比较器Class:
class CompareByVotes implements Comparator<Post> {
@Override
public int compare(Post t1, Post t2) {
int diff = ((Integer) t2.votes).compareTo(t1.votes);
if (diff == 0) {
return ((Integer) t2.id).compareTo(t1.id);
}
return diff;
}
}
问题:
是否需要进行任何更改才能使其按预期工作?
当您根据 equals()
方法比较的对象相等时,您的 compareTo()
方法不会 return 0
。但是,这是 SortedSet
接口所要求的:
Note that the ordering maintained by a sorted set (whether or not an explicit comparator is provided) must be consistent with equals if the sorted set is to correctly implement the
Set
interface. (See theComparable
interface orComparator
interface for a precise definition of consistent with equals.) This is so because theSet
interface is defined in terms of the equals operation, but a sorted set performs all element comparisons using itscompareTo
(or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the sorted set, equal. The behavior of a sorted set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of theSet
interface.
因此当它们相等时,您的 compareTo()
方法必须 return 0
。一种可能的解决方案是这样的:
public int compareTo(Post t) {
if (equals(t)) {
return 0;
}
int diff = ((Integer) t.votes).compareTo(this.votes);
if (diff == 0) {
return ((Integer) t.id).compareTo(this.id);
}
return diff;
}
此外,请记住 add()
不会“覆盖”对象,当集合中已经存在相同的对象时。请参阅 add()
的文档:
[...] If this set already contains the element, the call leaves the set unchanged and returns false.