java 使用 Set - 自动删除重复项?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17222226/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 01:21:13  来源:igfitidea点击:

Using Set - Removes duplicates automatically?

javacollectionssetduplicates

提问by Kevin Rave

I have a class as below (Bean):

我有一个如下类(Bean):

class KeysHolder {
   Long kitId;
   String packId;
   String boxId;

   // getters and setters
    .......
   // @Override equals and hashCode
}

I have a set that contains the above Objects

我有一个包含上述对象的集合

 Set<KeysHolder> keys;

Now if I keep adding the object to the set, does it automatically remove duplicates based on the values of the each elements? (I understand it uses Overridden equals and hashCode methods internally).

现在,如果我继续将对象添加到集合中,它是否会根据每个元素的值自动删除重复项?(我知道它在内部使用 Overridden equals 和 hashCode 方法)。

The final set should not contain any duplicates based on each field equality.

根据每个字段的相等性,最终集合不应包含任何重复项。

  obja.kitId = objb.kitId
  objb.packid = objb.packId
  obja.boxId = objb.boxId

Thanks!

谢谢!

回答by NINCOMPOOP

Now if I keep adding the object to the set, does it automatically remove duplicates based on the values of the each elements.

现在,如果我继续将对象添加到集合中,它是否会根据每个元素的值自动删除重复项。

The element if found duplicate by the Setimplementation ,wouldn't be inserted at all.

如果实现发现元素重复Set,则根本不会插入该元素。

From the Javadocs of HashSet#add(E e):

来自HashSet#add(E e)的 Javadocs :

Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if this set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false.

如果指定的元素尚不存在,则将其添加到此集合中。更正式地,如果该集合不包含元素 e2 使得(e==null ? e2==null : e.equals(e2)),则将指定的元素 e 添加到该集合中。如果此集合已包含该元素,则调用将保持该集合不变并返回 false。

回答by Ravi Thapliyal

Yes, any Setimplementation would not allow duplicates.

是的,任何Set实现都不允许重复。

But, it comes with a caveat. For a Setand other hash-based collections you need to make sure that the objects that you try to insert override their equals()as well as hashCode()method correctly.

但是,它有一个警告。对于 aSet和其他基于散列的集合,您需要确保您尝试插入的对象正确覆盖它们equals()以及hashCode()方法。

By correct, I mean that equals()should return truefor two meaningfully equivalent objects and that the hashCode()should try to return as disparate values as possible for the range of objects in your input set.

正确的是,我的意思是equals()应该返回true两个有意义的等效对象,并且hashCode()应该尝试为输入集中的对象范围返回尽可能不同的值。

While an improper equals()implementation would most likely break your program; an inefficient hashCode()implementation would degrade your Set's performance i.e. operations like add(), contains()etc. would be as slow as bad the implementation.

虽然不正确的equals()实现很可能会破坏您的程序;低效的hashCode()实施将降低你Set的表现,即操作一样add()contains()等会慢糟糕的实现。

回答by Costi Ciudatu

The short answer is yes, any set will perform the de-duplication by itself. But that's only guaranteed if you respect the contract; and the contract is a bit different for each Setimplementation:

简短的回答是肯定的,任何集合都将自行执行重复数据删除。但这只有在您尊重合同的情况下才能得到保证;并且每个Set实现的合约都有些不同:

For a HashSet, as you noticed, you have to implement hashCode()and equals(). But that's not enough: if you keep mutableinstances in a HashSetand you modify the properties which affect the hashCode()/equals()result, you'll still end up in a weird situation.

对于 a HashSet,正如您所注意到的,您必须实现hashCode()equals()。但这还不够:如果您在 a 中保留可变实例HashSet并修改影响hashCode()/equals()结果的属性,您仍然会遇到奇怪的情况。

With a TreeSet, on the other hand, you need to make sure that your Comparable.compareTo()or Comparator.compare()methods are consistent with equals().

TreeSet另一方面,使用 a 时,您需要确保您的Comparable.compareTo()Comparator.compare()方法与equals().

So read the documentation of Setand the one of the actual implementation that suits your needs and try to stick to the contract.

因此,请阅读Set适合您需求的实际实现的文档和其中之一,并尝试遵守合同。

回答by zerocool

HashSet internally uses HashMap, this map is maintained with key as the value that you want to add in the set and value is an instance of an Object class( final private static final Object PRESENT = new Object();). Now, when you add same object to this set, its the same operation that map does when you do map.put with the same on the same key, just updating the value.

HashSet 内部使用 HashMap,此映射以键作为要添加到集合中的值进行维护,值是一个 Object 类的实例(final private static final Object PRESENT = new Object();)。现在,当你向这个集合添加相同的对象时,它的操作与 map 在你对相同的键执行相同的 map.put 时所做的操作相同,只是更新值。

However the value to be updated still remains the same which is PRESENT. And hence in a way you can say that set does not add samevalue. Though actually, map which is used internally to implement this set is updating itself with *samekey* and same value(PRESENT).

然而,要更新的值仍然保持不变,即PRESENT。因此,在某种程度上,您可以说 set 不会添加相同的值。尽管实际上,内部用于实现此集合的映射正在使用*相同的* 和相同的值(PRESENT)更新自身。

回答by Saurav Sahu

I have written an example to illustrate how to remove duplicate employee entry in a set based one field in the class, here name:

我写了一个例子来说明如何在基于类中的一个字段的集合中删除重复的员工条目,这里name

public class Employee {
    private String id;
    private String name;
    private String age;
    public Employee(String i, String n, String a) {
        id = i; name = n; age = a;
    }
    @Override
    public boolean equals(Object obj) {
        if (obj == this) { 
            return true; 
        } 

        if (!(obj instanceof Employee)) { 
            return false; 
        }

        Employee e = (Employee) obj;

        return name.equals(e.name); 
    }
    @Override
    public int hashCode() {
        return name.hashCode();
    }
    @Override
    public String toString() {
        return id + " " + name + " " + age;
    }
    public static void main(String[] args) {
        Employee e1 = new Employee("1", "abc", "10");
        Employee e2 = new Employee("2", "def", "20");
        Employee e3 = new Employee("3", "abc", "30");
        HashSet<Employee> empSet = new HashSet<>();
        empSet.add(e1);
        empSet.add(e2);
        empSet.add(e3);
        System.out.println(empSet.toString());
    }
}

All I needed to do is override methods hashCodeand equalsin Employee class. It prints:

我需要做的就是覆盖方法hashCodeequalsEmployee 类。它打印:

[1 abc 10, 2 def 20]