繁体   English   中英

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

[英]How to remove duplicates from a list?

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

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

假设您想保持当前顺序而不需要Set ,也许最简单的方法是:

List<Customer> depdupeCustomers =
    new ArrayList<>(new LinkedHashSet<>(customers));

如果要更改原始列表:

Set<Customer> depdupeCustomers = new LinkedHashSet<>(customers);
customers.clear();
customers.addAll(dedupeCustomers);

如果您问题中的代码不起作用,您可能没有在Customer类上适当地实现equals(Object)

大概有一些唯一标识客户的密钥(让我们称之为customerId ); 例如

class Customer {
    private String customerId;
    ...

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);
    }

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

    public int hashCode() {
        return customerId.hashCode();
    }

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

Java 8 更新
您可以使用数组流,如下所示:

Arrays.stream(yourArray).distinct()
                    .collect(Collectors.toList());

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

只需将所有元素添加到Set :它不允许重复它的元素。 如果您之后需要一个列表,请在之后使用 new ArrayList(theSet)构造函数(其中theSet是您的结果集)。

客户是否实施了equals()合同?

如果它没有实现equals()hashCode() ,那么listCustomer.contains(customer)将检查列表中是否已经存在完全相同的实例(通过实例我的意思是完全相同的对象 - 内存地址等)。 如果您正在寻找的是测试相同的客户(如果他们具有相同的客户名称或客户编号,则可能是同一个客户)是否已经在列表中,那么您需要覆盖equals()以确保它检查相关字段(例如客户名称)是否匹配。

注意:如果您要覆盖equals()请不要忘记覆盖hashCode() equals() 否则,您的 HashMap 和其他数据结构可能会出现问题。 要详细了解为什么会这样以及要避免哪些陷阱,请考虑查看 Josh Bloch 关于equals()hashCode()Effective Java章节(该链接仅包含有关在实现equals()时为什么必须实现hashCode() equals() ,但也有关于如何覆盖equals()很好的报道)。

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

Set<Customer> noDups = new HashSet<Customer>();
noDups.addAll(tmpListCustomer);
return new ArrayList<Customer>(noDups);

这将很好地为您删除重复项,因为 Sets 不允许重复项。 但是,这将丢失任何应用于tmpListCustomer ,因为HashSet没有明确的排序(您可以通过使用TreeSet来解决这个问题,但这与您的问题并不完全相关)。 这可以稍微简化您的代码。

我怀疑您可能没有正确(或根本没有Customer.equals()实现Customer.equals() ) 。

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

以下是有关如何实现equals (和hashCode ,这是它的对 - 如果需要实现它们中的任何一个,实际上必须始终实现两者)的详细信息。 由于您没有向我们展示 Customer 类,因此很难给出更具体的建议。

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

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());

}

“包含”方法搜索列表是否包含从 Customer.equals(Object o) 返回 true 的条目。 如果您没有覆盖 Customer 或其父对象之一中的 equals(Object),那么它只会搜索同一对象的现有出现。 这可能是您想要的,在这种情况下您的代码应该可以工作。 但是,如果您希望没有两个对象同时代表同一客户,那么您需要覆盖 equals(Object) 以在这种情况下返回 true。

同样,使用 Set 而不是 List 的实现之一会自动且更快地删除重复项(对于非常小的列表以外的任何内容)。 您仍然需要为 equals 提供代码。

当您覆盖 equals() 时,您还应该覆盖 hashCode()。

几乎所有上述答案都是正确的,但我建议在创建相关列表时使用 Map 或 Set,而不是在获得性能之后。 因为将列表转换为 Set 或 Map,然后再将其重新转换为 List 是一项微不足道的工作。

示例代码:

Set<String> stringsSet = new LinkedHashSet<String>();//A Linked hash set 
//prevents the adding order of the elements
for (String string: stringsList) {
    stringsSet.add(string);
}
return new ArrayList<String>(stringsSet);

两个建议:

  • 使用 HashSet 而不是 ArrayList。 如果你有一个很长的列表,这将大大加快 contains() 检查

  • 确保 Customer.equals() 和 Customer.hashCode() 正确实现,即它们应该基于客户对象中基础字段的组合值。

最干净的方法是:

List<XXX> lstConsultada = dao.findByPropertyList(YYY);
List<XXX> lstFinal = new ArrayList<XXX>(new LinkedHashSet<GrupoOrigen>(XXX));

并覆盖每个实体的 Id 属性的hascodeequals

正如其他人所提到的,您可能没有正确实现 equals()。

但是,您还应该注意,此代码被认为效率很低,因为运行时可能是元素数的平方。

您可能需要考虑使用 Set 结构而不是 List,或者先构建 Set 然后将其转换为列表。

恕我直言,这些天最好的做法是:

假设您有一个“ dups ”集合,并且您想创建另一个包含相同元素但消除所有重复项的集合。 下面的单行代码可以解决问题。

Collection<collectionType> noDups = new HashSet<collectionType>(dups);

它通过创建一个根据定义不能包含重复项的 Set 来工作。

基于 oracle 文档。

Java 的正确答案是使用Set 如果你已经有一个List<Customer>并且想要去重复它

Set<Customer> s = new HashSet<Customer>(listCustomer);

否则直接使用Set实现HashSetTreeSet并跳过List构建阶段。

您还需要覆盖放在Set中的域类上的hashCode()equals() ,以确保您想要的行为实际上是您获得的。 equals()可以像比较对象的唯一 id 一样简单,也可以像比较每个字段一样复杂。 hashCode()可以简单为返回hashCode()中的唯一ID”的String表示或hashCode()

使用 java 8 流 api。

    List<String> list = new ArrayList<>();
    list.add("one");
    list.add("one");
    list.add("two");
    System.out.println(list);
    Collection<String> c = list.stream().collect(Collectors.toSet());
    System.out.println(c);

输出:

值之前:[一,一,二]

后值:[一,二]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM