【问题标题】:Replacing a HashSet Java member替换 HashSet Java 成员
【发布时间】:2012-11-07 00:10:00
【问题描述】:

我有那个结构的集合。我没有重复,但是当我打电话时: set.add(element) -> 已经有确切的元素我想替换旧的。

import java.io.*;

public class WordInfo implements Serializable {
    File plik;
    Integer wystapienia;

    public WordInfo(File plik, Integer wystapienia) {
        this.plik = plik;
        this.wystapienia = wystapienia;
    }

    public String toString() {
    //  if (plik.getAbsolutePath().contains("src") && wystapienia != 0)
            return plik.getAbsolutePath() + "\tWYSTAPIEN " + wystapienia;
    //  return "";
    }
    @Override
    public boolean equals(Object obj) {
        if(this == obj) return true;
        if(!(obj instanceof WordInfo)) return false;
        return this.plik.equals(((WordInfo) obj).plik);
    }

    @Override
    public int hashCode() {        
        return this.plik.hashCode();
    }
}

【问题讨论】:

  • 无法理解代码sn-p与问题的关系。你能解释一下,在你的代码中设置它在哪里?另外,如果你的对象完全一样,那你为什么要替换?
  • @YogendraSingh - OP 希望能够用较新的 equals() 替换集合中的旧 WordInfo,但不是同一个对象。 (注意equals() 测试忽略了wystapienia 的值。)
  • @TedHopp:谢谢,但return this.plik.equals(((WordInfo) obj).plik); 仍然会返回true,不是吗??
  • @YogendraSingh - 我的意思是两个WordInfo 对象可以是equals() 而不是==。当两个是equals() 而不是== 时,OP 希望能够在Set 中用另一个替换一个。 OP 的问题是:如何进行替换。
  • @TedHopp:我试图用 OP 来理解问题本身,即why?,我仍然不相信(可能这是伪示例)。我看到你对how 的回答,这很好。我现在就离开它。感谢您的投入。

标签: java replace set duplicates


【解决方案1】:

检查 JDK 中的 HashSet 代码。 当添加元素并且是重复元素时,旧值将被替换。 民间认为新元素被丢弃,这是错误的。 因此,您不需要额外的代码。

已更新---------------------

我重新阅读了 JDK 中的代码,并承认我犯了一个错误。

put 生成时,替换的是HashMap 中的VALUE 而不是KEY。

我为什么要说Hashmap??!!因为如果您查看HashSet 代码,您会注意到:

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

因此PRESENT 值被替换为新值,如这部分代码所示:

      public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

但我同意,key 没有被替换,并且由于 keys 代表 HashSet's 值,因此这个值被称为“未触及”。

【讨论】:

  • 这是一个内部实现细节,应该被依赖。
  • 如果发生替换,则 HashSet 未遵循 Add 的 Set 约定:“调用使集合保持不变并返回 false”
  • -1 这完全是错误的:相同的哈希码并不意味着相同的对象。新元素丢弃!见javadocIf this set already contains the element, the call leaves the set unchanged and returns false
  • @Bohemian 我从来没有说过我在谈论相同的哈希码。谈论相同的对象。
  • 我已经运行了一个测试,我很高兴确认 HashSet 确实符合 Set 合同,保留旧对象以防尝试添加一个等于Set 的现有元素。
【解决方案2】:

尝试如下操作(这只有在 equalshashCode 依赖于一个字段时才有意义,但其他字段可能具有不同的值):

if(!set.add(obj)) {
    //set already contains the element (not the same object though) 
    set.remove(obj); //remove the one in  the set
    set.add(obj); //add the new one
}

查看Set.add 方法的文档

如果该集合已经包含该元素,则调用保持该集合不变并返回 false。

【讨论】:

  • -1 这行不通。无论set() 返回什么,您总是想添加
  • ok no -1,但现在你的答案和 Patricia 的一样,她是第一个回答“正确”的人
【解决方案3】:

在每次添加之前进行删除:

 someSet.remove(myObject);
 someSet.add(myObject);

remove 将删除任何等于 myObject 的对象。或者,您可以检查添加结果:

 if(!someSet.add(myObject)) {
     someSet.remove(myObject);
     someSet.add(myObject);
 }

哪种方式更有效取决于您发生碰撞的频率。如果它们很少见,第二种形式通常只做一次操作,但当发生碰撞时,它会做三次。第一种形式总是做两个。

【讨论】:

  • 这会导致我 Exception in thread "main" java.util.ConcurrentModificationExceptionIterator 一起使用时
  • @ThreaT 这是与此问题不同的问题,该问题是关于在可以调用 add 的情况下更改其行为。我建议将其作为一个新问题提出,其背景比你可以发表的评论要多,除非你能找到对你有帮助的现有问题。
  • hmm,那我们可以用简单的List代替Set
  • 第二个代码块中的 if 语句可以简化为 if(someSet.remove(myObject))...,因为如果集合中存在 myObjectremove 方法也会返回 true。我还认为contains 对于 if 语句会更有效,但在运行 if 语句的内容时整体效率会降低。
【解决方案4】:

如果集合中已经包含一个元素,equals() 是您尝试添加的元素,则不会添加新元素,也不会替换现有元素。为保证添加了新元素,只需先将其从集合中移除即可:

set.remove(aWordInfo);
set.add(aWordInfo);

【讨论】:

  • 就像一分钟前一样 :) 工作
【解决方案5】:

我正在解决一个问题,我有一个集合,然后我想用另一个集合中的对象替换/覆盖一些对象。

在我的情况下,我最终做的是创建一个新集合并首先放置覆盖,然后再添加当前对象。这是因为在添加新对象时集合不会替换任何现有对象。

如果你有:

Set<WordInfo> currentInfo;
Set<WorldInfo> overrides;

代替:

for each override, replace the object in current info

我做到了:

Set<WordInfo> updated = new HashSet<>();
updated.addAll(overrides);
updated.addAll(currentInfo);

【讨论】:

    猜你喜欢
    • 2018-08-03
    • 1970-01-01
    • 2015-12-23
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 2020-05-05
    • 1970-01-01
    • 2021-07-11
    相关资源
    最近更新 更多