在不覆盖 hashCode() 的情况下删除重复项
Removing duplicates without overriding hashCode()
出于企业原因我无法覆盖hashCode
,我必须使用Java 6(但我可以使用番石榴)
从 Java 集合中删除重复 bean 的 bests/simplest/quickest/most 高效/[插入与最佳等效的不确定形容词] 机制是什么?
重复由返回相同值的 getter 子集定义,例如
pojoA.getVal() == pojoB.getVal() && pojoA.getOtherVal() == pojoB.getOtherVal()
将感兴趣的对象包装到您自己的 class 中,并覆盖其 hashCode
/equals
以关注特定的属性子集。制作包装器的哈希集,然后从集合中收集对象以获得无重复的子集。
这是一个例子:
class ActualData {
public String getAttr1();
public String getAttr2();
public String getAttr3();
public String getAttr4();
}
假设您想关注属性 1、2 和 4。那么您可以像这样制作一个包装器:
class Wrapper {
private final ActualData data;
public ActualData getData() {
return data;
}
private final int hash;
public Wrapper(ActualData data) {
this.data = data;
this.has = ... // Compute hash based on data's attr1, 2, and 4
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Wrapper)) return false;
Wrapper other = (Wrapper)obj;
return data.getAttr1().equals(other.getAttr1())
&& data.getAttr2().equals(other.getAttr2())
&& data.getAttr4().equals(other.getAttr4());
}
}
现在你可以制作 HashSet<Wrapper>
:
Set<Wrapper> set = new HashSet<>();
for (ActualData item : listWithDuplicates) {
if (!set.add(new Wrapper(item))) {
System.out.println("Item "+item+" was a duplicate");
}
}
您可以使用带有比较器的 new TreeSet<Pojo> (comparator)
来反映您的条件(假设此处为整数,但根据需要替换 - 对于不可比较的对象,您需要找到 return 一些整数的 hack)。
if (pojoA.getVal() != pojoB.getVal())
return Integer.compare(pojoA.getVal(), pojoB.getVal());
if (pojoA.getOtherVal() != pojoB.getOtherVal())
return Integer.compare(pojoA.getOtherVal(), pojoB.getOtherVal());
return 0;
尽管效率不如普通 HashSet - @dasblikenlight 建议可能更好。
出于企业原因我无法覆盖hashCode
,我必须使用Java 6(但我可以使用番石榴)
从 Java 集合中删除重复 bean 的 bests/simplest/quickest/most 高效/[插入与最佳等效的不确定形容词] 机制是什么?
重复由返回相同值的 getter 子集定义,例如
pojoA.getVal() == pojoB.getVal() && pojoA.getOtherVal() == pojoB.getOtherVal()
将感兴趣的对象包装到您自己的 class 中,并覆盖其 hashCode
/equals
以关注特定的属性子集。制作包装器的哈希集,然后从集合中收集对象以获得无重复的子集。
这是一个例子:
class ActualData {
public String getAttr1();
public String getAttr2();
public String getAttr3();
public String getAttr4();
}
假设您想关注属性 1、2 和 4。那么您可以像这样制作一个包装器:
class Wrapper {
private final ActualData data;
public ActualData getData() {
return data;
}
private final int hash;
public Wrapper(ActualData data) {
this.data = data;
this.has = ... // Compute hash based on data's attr1, 2, and 4
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Wrapper)) return false;
Wrapper other = (Wrapper)obj;
return data.getAttr1().equals(other.getAttr1())
&& data.getAttr2().equals(other.getAttr2())
&& data.getAttr4().equals(other.getAttr4());
}
}
现在你可以制作 HashSet<Wrapper>
:
Set<Wrapper> set = new HashSet<>();
for (ActualData item : listWithDuplicates) {
if (!set.add(new Wrapper(item))) {
System.out.println("Item "+item+" was a duplicate");
}
}
您可以使用带有比较器的 new TreeSet<Pojo> (comparator)
来反映您的条件(假设此处为整数,但根据需要替换 - 对于不可比较的对象,您需要找到 return 一些整数的 hack)。
if (pojoA.getVal() != pojoB.getVal())
return Integer.compare(pojoA.getVal(), pojoB.getVal());
if (pojoA.getOtherVal() != pojoB.getOtherVal())
return Integer.compare(pojoA.getOtherVal(), pojoB.getOtherVal());
return 0;
尽管效率不如普通 HashSet - @dasblikenlight 建议可能更好。