【问题标题】:Java Set with multiple equality criteria具有多个相等条件的 Java Set
【发布时间】:2015-10-20 12:14:11
【问题描述】:

我有一个特殊要求,我需要根据相等标准的组合对对象列表进行重复数据删除。

例如两个 Student 对象相等,如果:
1. firstName 和 id 相同或 2. lastName、class 和 emailId 相同

我打算使用Set 删除重复项。但是,有一个问题:
我可以覆盖equals 方法,但hashCode 方法可能不会为两个相等的对象返回相同的哈希码。

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;

    Student other = (Student) obj;
    if ((firstName.equals(other.firstName) && id==other.id) ||
            (lastName.equals(other.lastName) && class==other.class && emailId.equals(other.emailId ))
        return true;        
    return false;
}

现在我不能重写 hashCode 方法,因为它会根据 equals 方法为两个相等的对象返回相同的哈希码。

有没有一种基于多个相等标准的重复数据删除方法?我考虑使用List,然后使用contains 方法检查元素是否已经存在,但这增加了复杂性,因为包含在O(n) 时间内运行。我不想为所有对象返回完全相同的哈希码,因为这只会增加时间并超出使用哈希码的目的。我也考虑过使用自定义比较器对项目进行排序,但这至少需要 O(n log n),再加上一次遍历以删除重复项。

到目前为止,我最好的解决方案是维护两个不同的集合,每个条件一个集合并使用它来构建一个List,但这几乎需要三倍的内存。我正在寻找一种更快且内存效率更高的方法,因为我将处理大量记录。

【问题讨论】:

  • “现在我不能重写 hashCode 方法,让它根据这个 equals 方法为两个相等的对象返回相同的哈希码” 你能解释一下你为什么这么说吗?
  • 查看@m0skit0 的评论。你的哈希码是错误的,如果它没有为相等的对象返回相同的值。
  • @m0skit0 那是hashCode的总合约:If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • 我知道 hashCode 合约,我的问题是实现它有什么问题。
  • @m0skit0 在我的 equals 方法中有一个 if-else 语句,所以 hashCodeequals 永远不会同步。考虑这个例子,如果我使用所有五个字段来计算hashCodeequals 将仅基于其中两个或三个。所以例如如果 firstNameid 相同,则对象相等,但其他三个值可能不同,因此这两个对象的 hashCode 也将不同。你可以试着去实现,你就会明白我在说什么。

标签: java hash set hashcode deduplication


【解决方案1】:

您可以制作Student Comparable 并使用TreeSetcompareTo的简单实现可能是:

@Override
public int compareTo(Student other) {
    if (this.equals(other)) {
        return 0;
    } else {
        return (this.firstName + this.lastName + emailId + clazz + id)
                .compareTo(other.firstName + other.lastName + other.emailId + clazz + id);
    }
}

或者制作自己的 Set 实现,例如包含不同 Student 对象的 List,每次添加学生时检查是否相等。这将有O(n) 增加复杂性,因此不能被认为是一个好的实现,但它很容易编写。

class ListSet<T> extends AbstractSet<T> {
    private List<T> list = new ArrayList<T>();

    @Override
    public boolean add(T t) {
        if (list.contains(t)) {
            return false;
        } else {
            return list.add(t);
        }
    }

    @Override
    public Iterator<T> iterator() {
        return list.iterator();
    }

    @Override
    public int size() {
        return list.size();
    }
}

【讨论】:

  • 这个答案可以通过显示一些代码来改进。
猜你喜欢
  • 2018-01-03
  • 2018-11-21
  • 2017-07-06
  • 2016-08-21
  • 1970-01-01
  • 2021-05-21
  • 2011-07-21
  • 1970-01-01
  • 2013-08-07
相关资源
最近更新 更多