如何从列表中删除重复项?

Mer*_*cer 55 java collections list duplicates

我想从列表中删除重复项,但我正在做的是不起作用:

List<Customer> listCustomer = new ArrayList<Customer>();    
for (Customer customer: tmpListCustomer)
{
  if (!listCustomer.contains(customer)) 
  {
    listCustomer.add(customer);
  }
 }
Run Code Online (Sandbox Code Playgroud)

Tom*_*ine 89

假设您想要保留当前订单并且不想要aSet,也许最简单的是:

List<Customer> depdupeCustomers =
    new ArrayList<>(new LinkedHashSet<>(customers));
Run Code Online (Sandbox Code Playgroud)

如果要更改原始列表:

Set<Customer> depdupeCustomers = new LinkedHashSet<>(customers);
customers.clear();
customers.addAll(dedupeCustomers);
Run Code Online (Sandbox Code Playgroud)

  • 如果你没有覆盖对象的(Customer's)equals方法,HashSet将比较对象在内存中的位置,这样它们就不会相等,你的新Set中仍然会有重复项. (3认同)
  • @GinjaNinja有一个隐含的假设,即`equals`(和`hashCode`)是以一种对类型有意义的方式实现的.例如,`LinkedHashSet <JWindow>`只会删除完全相同的对象的重复项,因为这对于`JWindow`实例来说意味着相同. (2认同)

Ste*_*n C 48

如果该代码不起作用,您可能没有适当地equals(Object)Customer类上实现.

据推测,有一些关键(我们称之为customerId)可以唯一地识别客户; 例如

class Customer {
    private String customerId;
    ...
Run Code Online (Sandbox Code Playgroud)

适当的定义equals(Object)将如下所示:

    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof Customer)) {
            return false;
        }
        Customer other = (Customer) obj;
        return this.customerId.equals(other.customerId);
    }
Run Code Online (Sandbox Code Playgroud)

为了完整性,您还应该实现,hashCode以便两个Customer相等的对象将返回相同的哈希值.hashCode上述定义的匹配equals将是:

    public int hashCode() {
        return customerId.hashCode();
    }
Run Code Online (Sandbox Code Playgroud)

值得注意的是,如果列表很大,这不是删除重复项的有效方法.(对于包含N个客户的列表,您将需要N*(N-1)/2在最坏的情况下执行比较;即,当没有重复时.)对于更有效的解决方案,您应该使用类似的东西HashSet来执行重复检查.


Ali*_*lah 25

java 8更新
你可以使用数组流如下:

Arrays.stream(yourArray).distinct()
                    .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • 您也可以使用TreeSet,但是您必须实现Comparable,这并不总是令人满意的 (2认同)

fol*_*one 13

列表→设置→列表(不同)

只需将所有元素添加到Set:它不允许重复元素.如果之后需要列表,请在之后使用新ArrayList(theSet)构造函数(theSet结果集在哪里).

  • 使用Set将产生与上面编写的代码完全相同的结果,速度更快.海报说"不起作用"而不是"工作太慢". (3认同)

Sco*_*nes 13

客户是否执行equals()合同?

如果不执行equals()hashCode(),然后listCustomer.contains(customer)将检查,看看是否完全相同的情况下在列表中已经存在(比如通过我的意思是完全相同的对象-内存地址等).如果您要查找的是测试同一客户(如果他们拥有相同的客户名称或客户编号,可能是同一客户)是否已在列表中,那么您需要覆盖equals()以确保它检查相关字段(例如客户名称)是否匹配.

注意:hashCode()如果您要覆盖,请不要忘记覆盖equals()!否则,您可能会遇到HashMaps和其他数据结构的问题.为了更好地了解为什么会这样,以及要避免哪些陷阱,请考虑查看Josh Bloch的Effective Java章节equals()hashCode()(该链接仅包含有关您实施hashCode()时必须实现的原因的iformation equals(),但有关如何覆盖的良好报道equals()太).

顺便问一下,您的套装是否有订购限制?如果没有,解决这个问题的一种稍微简单的方法是使用Set<Customer>如下:

Set<Customer> noDups = new HashSet<Customer>();
noDups.addAll(tmpListCustomer);
return new ArrayList<Customer>(noDups);
Run Code Online (Sandbox Code Playgroud)

哪个会很好地删除重复项,因为集合不允许重复.但是,这将失去任何应用的排序tmpListCustomer,因为HashSet没有明确的排序(你可以通过使用a TreeSet,但这与你的问题不完全相关).这可以简化您的代码.

  • 如果您需要维护订单,则无法使用+1来记住该Set. (3认同)

Pét*_*rök 9

我怀疑你可能没有Customer.equals()正确实施(或根本没有).

List.contains()用于equals()验证其任何元素是否与作为参数传递的对象相同.但是,equals物理身份测试的默认实现,而不是值身份.因此,如果您没有覆盖它Customer,它将为具有相同状态的两个不同Customer对象返回false.

以下是如何实现equals的细节(以及hashCode哪一个 - 如果您需要实现其中任何一个,您必须实际上始终实现这两者).由于您尚未向我们展示Customer类,因此很难提供更具体的建议.

正如其他人所指出的那样,你最好使用Set而不是手工完成工作,但即便如此,你仍然需要实现这些方法.


小智 6

private void removeTheDuplicates(List<Customer>myList) {
    for(ListIterator<Customer>iterator = myList.listIterator(); iterator.hasNext();) {
        Customer customer = iterator.next();
        if(Collections.frequency(myList, customer) > 1) {
            iterator.remove();
        }
    }
    System.out.println(myList.toString());

}
Run Code Online (Sandbox Code Playgroud)


DJC*_*rth 5

"contains"方法搜索列表是否包含从Customer.equals(Object o)返回true的条目.如果您没有在Customer或其父项之一中重写equals(Object),那么它将仅搜索同一对象的现有匹配项.这可能是你想要的,在这种情况下你的代码应该工作.但是,如果您正在寻找没有两个对象同时代表同一个客户,那么在这种情况下,您需要覆盖equals(Object)以返回true.

使用Set而不是List的一个实现也可以自动,快速地为您提供重复删除(除了非常小的列表之外的任何其他内容).您仍然需要提供equals代码.

覆盖equals()时,还应覆盖hashCode().