【问题标题】:Preventing duplicates while adding to set添加到集合时防止重复
【发布时间】:2014-05-11 23:21:06
【问题描述】:

情况:

假设我有一个这样的类:

class Person {
    public String name;
    public String surname;
    public age;
}

现在我想根据一些先前创建的列表(包含一些重复项)创建一个包含一些人的集合。当然,当我创建集合时,我不想在里面有任何重复。

HashSet<Person> mySet = new LinkedHashSet<Person>(listOfPeople);

问题: 让我们假设,在某些情况下,“无重复” 对我来说意味着 “不同名字的人”。在其他情况下“不同年龄的人”等等。

我看到HashSetadd 方法使用来自HashMapput

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        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;
    }

问题: 所以,我知道我应该简单地覆盖Person 中的equals,并记住根据我的要求为应该“相等”的对象返回相同的hashCode。但是如果我的“平等”术语在运行时发生变化怎么办?

我在问,因为在使用Collections.sort 对集合进行排序时,我可以指定自定义Comparator,这使我能够根据情况提供比较逻辑。

是否有任何你知道的类比机制或解决方案,使我能够在运行时决定创建一组元素时组件是否相等?

我现在唯一的解决方案是在 Person 类中定义一些静态 Comparator,然后以它使用此比较器的方式覆盖一个 equals 方法。然后,通过替换 Person 中的 Comparator,我实际上是在更改 equals 逻辑......这有意义吗?

【问题讨论】:

    标签: java duplicates add hashset comparator


    【解决方案1】:

    我现在唯一的解决方案是在 Person 类中定义一些静态比较器,然后以使用此比较器的方式覆盖一个 equals 方法

    不要那样做。 Comparator 合约中没有任何内容要求两个与 .equals() 不同的对象比较非零。唯一可以设置的约束是if 两个对象是.equals(),然后相互比较它们给出0。然后Comparable 的实现被称为“与equals 兼容”。但是有些类在 JDK 中甚至不尊重这一点(参见 BigDecimal)。

    你有两个选择:

    • 使用SortedSet。例如,TreeSet 允许您在运行时传递 ComparatorSortedSet 评估等价于以下事实,即两个实例相互比较得出 0,而不管 .equals()
    • 如果你使用Guava,你可以为你的对象创建一个或多个Equivalences;你的Set 必须有Equivalence.Wrapper&lt;Person&gt; 类型的成员,而不仅仅是Person,你必须.add(eq.wrap(person)),但它有效。

    【讨论】:

    • 是的,“包装器”关键字也在我的脑海中!我以为是很多并发症。但可能不是。感谢您的提示!
    【解决方案2】:

    您可以将TreeSet&lt;Person&gt; 与您自己的比较器一起使用

    【讨论】:

      【解决方案3】:

      您必须在您的 Person 类中进行一些修改并使用这个自定义的 hashSet

      public class CustomHashSet extends HashSet {        
          @Override
          public boolean add(Object e) {
              boolean flag  = true;
              Iterator<Object> itr = this.iterator();
              while(itr.hasNext()){
                  if(itr.next().hashCode()==(e.hashCode())){
                      flag = false;
                      break;
                  }
              }
              if(flag)
                  flag = flag & super.add(e);
              return flag;
          }   
      
      }
      

      修改person类

      public class Person {
      
          public String name;
          public String surname;
          public int age;
      
      
          @Override
          public boolean equals(Object obj) {
               return (this == obj); 
          }
      
          @Override
          public int hashCode() {
                int result = name.hashCode();
                  result = 31 * result + age;
                  return result;
          }
      }
      

      在哈希码方法重复检查中使用您自己的逻辑。

      测试

      public class TestB {
      
      public static void main(String[] args) {
          HashSet a = new CustomHashSet();
          Person p = new Person("test","test1",1);
          Person p1 = new Person("test","test1",1);
          a.add(p);
          a.add(p1);
          System.out.println(a);
      }
      

      } 这将只添加一个元素,不允许重复元素。 希望这对你有帮助。 你也可以使用类似的接口实现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-20
        • 2023-04-08
        • 1970-01-01
        相关资源
        最近更新 更多