【问题标题】:HashSet not removing all duplicate entriesHashSet 没有删除所有重复的条目
【发布时间】:2016-11-02 14:13:47
【问题描述】:

我正在尝试使用 HashSet 来确保我从 .txt 文件中读取的数据是唯一的。

以下是样本数据;

999990  bummer
999990  bummer
999990  bummer
999990  bummer
99999   bummer
999990  bummerr

使用 Java.io.File 和 Java.util.Scanner 读取并存储为 Term 对象;

阅读术语;

while (rawTerms.hasNextLine()){
    String[] tokens = rawTerms.nextLine().trim().split(delimiter);
    if (tokens.length == 2) {               
        uniqueSet.add(new Term(Double.parseDouble(tokens[0]), tokens[1])); //add the term to set
    }
    else {
      rawTerms.close();
      throw new Exception("Invalid member length: "+ tokens.length);
    }           
}

allTerms = new ArrayList<>(uniqueSet); //Covert set into an ArrayList

使用 Guava 的术语类;

public Term(double weight, String theTerm){
    this.weight = weight;
    this.theTerm = theTerm;
}


@Override
public boolean equals(final Object obj) {
    if (obj instanceof Term){
        final Term other = (Term) obj;
        return Objects.equal(this.weight, other.weight)
                && Objects.equal(this.theTerm, other.theTerm);
    }
    else {
        return false;
    }
}

@Override
public String toString(){
    return toStringHelper(this).addValue(weight)
            .addValue(theTerm).toString();

}

@Override  
public int hashCode() {  
    return Objects.hashCode(this.weight, this.theTerm);  
}

但是,当我运行测试以检查存储条目的数组的大小时,我得到了 3 个条目,而不是我想要的 1 个。我希望任何与之前添加的条目具有相同权重或术语的新条目都被视为重复条目。

感谢所有帮助!

马特

【问题讨论】:

  • 什么是uniqueSet
  • 您的格式非常...不稳定。发布前请在 IDE 中自动格式化;并确保您的格式是一致的。另请注意,Java 首选埃及方括号。最后,如果您有return,则不需要else
  • @BoristheSpider 我从来没有去过埃及,也没有导入他们的括号,但我已经编程多年了。开个玩笑,我认为花括号会在埃及人的脑海中唤起其他人想要的想法。 :)
  • 埃及方括号大括号。这是关于他们的位置。
  • @EdwinBuck 花括号是括号的类型 ({})。 Egyptian brackets(链接中的 3)是一种格式化代码块的样式,在 Java 中优于 K&R C style brackets

标签: java eclipse guava


【解决方案1】:

我希望任何与之前添加的条目具有相同权重或术语的新条目都被视为重复条目。

这不是平等的运作方式。平等必须是可传递的 - 所以如果x.equals(y) 返回真,而y.equals(z) 返回真,那么x.equals(z) 必须返回真。

这不是你想要的关系。

请注意,这也不是您的 equals 方法目前检查的内容:

return Objects.equal(this.weight, other.weight)
    && Objects.equal(this.theTerm, other.theTerm);

只有当权重匹配时才返回真,这对于相等关系是正常的。这就是为什么您会在您的集合中获得三个条目 - 因为以这种方式查看时,您确实拥有三个不同的实体。

从根本上说,HashSet 和所有其他处理平等的集合不会以简单的方式帮助您。您需要拥有三个独立的集合:

  • 一组权重
  • 一组术语
  • 一组(或列表)条目。

如果您正在考虑的条目在权重集合中具有权重在一组术语中,您应该跳过它 - 否则,您应该在每个条目中添加一个条目三个系列。

【讨论】:

  • 这组条目可以变成一个简单的列表。
  • @MarkoTopolnik:确实。我不确定是否要添加...会稍微修改一下。
  • 我的意思是,由于 Term 上不再定义自定义相等性,每个实例都在其自己的相等类中。因此,集合只不过是开销。
  • @MarkoTopolnik:好吧,OP可能想保持平等,他们可能想把它作为一个集合来强调排序无关紧要。
  • 静态类型可以是Collection,表示没有隐含的排序语义。但是......让我们不要陷入这个。
【解决方案2】:

考虑到hashCode(和equals)在Term 类中的实现,您应该期望 3 个条目,对应于所涉及的对:

999990  bummer
99999   bummer
999990  bummerr

hashCodeequals 都评估该对的两个属性,即 weight doubletheTerm String

该集合将通过比较哈希码来评估不等式,这对于上面列出的 3 个元素来说是不同的。

【讨论】:

  • TS 有重复的问题。您的回答没有解释为什么会这样。
  • 它没有回答 OP 试图实现的目标:“我希望任何与之前添加的条目具有相同权重或术语的新条目都被视为重复条目。”
  • 我现在知道我应该期待 3 个条目。但是,我的目标是 1 个独特的条目。也许下面的@JonSkeet 建议(对每个使用单独的集合)可以解决我的问题?
  • @MathanaSreedaran Jon Skeet 的答案每次都值得一试。如果我必须在此处添加任何内容:请考虑条目唯一所需的标准。例如,99999099999bummerbummerr 之间的“差异”。由于这很难一概而论,您可能需要实现自己的集合类型来迭代先前的条目并根据您尝试添加的对的术语检查该对的每个术语。不过,这在性能方面可能会变得非常低效。
猜你喜欢
  • 2018-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-04
  • 1970-01-01
相关资源
最近更新 更多