在 TreeMap 中的 Key 上对自定义数据结构进行排序
我正在尝试按键对 TreeMap 进行排序。 Key 是一些自定义的 DataStructure,具有 int、List、String 等。 我期望对其进行排序的成员有一些重复项。假设该成员是 Rank。超过 1 个对象可以具有相同的等级。
简化版本示例:
注意:在 CompareTo 方法中,不会有意返回 0,以不忽略重复项。(如果这不是避免重复项的正确方法,请纠正我)
import java.util.TreeMap;
public class TreeTest {
public static void main(String[] args) {
TreeMap<Custom,String> t = new TreeMap<Custom,String>();
Custom c1 = new Custom();
c1.setName("a");
c1.setRank(0);
Custom c2 = new Custom();
c2.setName("b");
c2.setRank(1);
Custom c3 = new Custom();
c3.setName("c");
c3.setRank(0);
t.put(c1, "first");
t.put(c2, "Second");
t.put(c3, "Third");
System.out.println(t.keySet());
for(Custom c:t.keySet()){
System.out.println(t.get(c));
}
}
}
和自定义对象
package com.example.ui;
public class Custom implements Comparable<Custom>{
int rank;
String name;
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + rank;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Custom other = (Custom) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (rank != other.rank)
return false;
return true;
}
// 0 is not returned intentionally to NOT ignore duplicates.
public int compareTo(Custom o) {
if(o.rank>this.rank)
return 1;
if(o.rank==this.rank)
return -1;
return -1;
}
}
输出::
[com.example.ui.Custom@fa0, com.example.ui.Custom@fbe, com.example.ui.Custom@f80] null null null
预期: 第一、第二、第三分别基于排名 0、1、0。
我在谷歌上看了几个例子。其中大多数是使用具有原始数据类型的键或值进行 TreeMap 排序的基本用法,但在对成员进行排序时没有重复项 是自定义键数据结构的一部分。
请帮忙?
I am trying to sort a TreeMap on key. Key is some custom DataStructure having int, List, String, etc.
The member on which I am expecting a sort has some duplicates. Let's say that member is Rank. More than 1 object can have same rank.
Simplified version example:
NOTE: in the CompareTo method below 0 is not returned intentionally to NOT ignore duplicates.(Please correct me if this is not the right way to avoid duplicates)
import java.util.TreeMap;
public class TreeTest {
public static void main(String[] args) {
TreeMap<Custom,String> t = new TreeMap<Custom,String>();
Custom c1 = new Custom();
c1.setName("a");
c1.setRank(0);
Custom c2 = new Custom();
c2.setName("b");
c2.setRank(1);
Custom c3 = new Custom();
c3.setName("c");
c3.setRank(0);
t.put(c1, "first");
t.put(c2, "Second");
t.put(c3, "Third");
System.out.println(t.keySet());
for(Custom c:t.keySet()){
System.out.println(t.get(c));
}
}
}
And Custom Object
package com.example.ui;
public class Custom implements Comparable<Custom>{
int rank;
String name;
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + rank;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Custom other = (Custom) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (rank != other.rank)
return false;
return true;
}
// 0 is not returned intentionally to NOT ignore duplicates.
public int compareTo(Custom o) {
if(o.rank>this.rank)
return 1;
if(o.rank==this.rank)
return -1;
return -1;
}
}
Output::
[com.example.ui.Custom@fa0, com.example.ui.Custom@fbe, com.example.ui.Custom@f80] null null null
Expected:
First, Second, Third based on Rank 0,1,0 respectively.
I looked at couple of examples on Google. Most of them were basic usage on TreeMap sort using keys or values with primitive datatypes, but none with duplicates when sorting member
is a part of custom key DataStructure.
Please help?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题是您的
compareTo
实现与TreeMap
。来自 API 文档:一种可能的一致实现是首先按排名进行比较,如果排名值相等则再按名称进行比较。对于两个具有相同等级和相同名称的 Custom 实例,您不应期望能够将它们作为键存储在同一个 Map 中 - 这违反了 Map 的约定。
The problem is that your implementation of
compareTo
is not consistent with equals, which is required byTreeMap
. From the API docs:One possible consistent implementation would be to first compare by rank and then by name if the rank values are equal. For two instances of Custom with equal ranks and identical names you should not expect to be able to store them both as keys within the same Map - This violates the contract of Map.
如前所述,您的 equals 和 CompareTo 实现彼此不一致。如果我正确地阅读了您的问题,您需要的是保留具有相同密钥的重复项。我建议您查看 TreeMultimap< /a> Google Guava 集合。它为每个值对象创建集合容器,以便保留具有相同键的不同值。
例如,
此数据结构中的约束是 K,V 对必须是唯一的。也就是说,您不能在 Multimap 中插入 ("rank1", "Joe") 两次。
一个重要的注意事项:您看到如此多使用简单类型(特别是字符串)的 Map 示例的原因是映射中的键必须是不可变的。对象的 equals 和 hashcode 值在用作映射中的键时不得更改。转换为您的示例,您无法执行
customObject.setRank(...)
并在将排名值用作键时更新排名值。为此,您首先需要删除键及其值,更新它,然后再次插入。As mentioned, your implementation of equals and compareTo are not consistent with each other. If I read your question correctly, what you require is to preserve duplicates that have the same key. I'd recommend you to look into the TreeMultimap of the Google Guava collections. It creates set containers for each value object sothat different values having the same key are preserved.
e.g.
The constrain in this data structure is that K,V pairs must be unique. That is, you can't insert ("rank1", "Joe") twice in the Multimap.
One important note: The reason why you see so many examples of Map, using simple types and, in particular, strings, is that keys in a map must be immutable. The equals and hashcode values of an object must not change in the time it's used as a key in a map. Translated to your example, you cannot do
customObject.setRank(...)
and updates a rank value when it's used as a key. To do so, you first need to remove the key and its values, update it and then insert it again.您还可以通过将 Comparator 实现为匿名内部类型并重写 Compare() 以返回所需的比较来实现此目的。
You can also do it by implementing Comparator as anonymous inner type and override compare() to return desired comparison.