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

时间:2010-05-17 13:37:33

标签: java list collections duplicates

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

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

15 个答案:

答案 0 :(得分:88)

假设您想保持当前订单并且不想要Set ,可能最简单的是:

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

如果您想更改原始列表:

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

答案 1 :(得分:48)

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

据推测,有一些关键字(我们称之为customerId)可以唯一地识别客户; e.g。

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,这样两个相等的Customer个对象将返回相同的哈希值。上述hashCode定义的匹配equals将为:

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

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

答案 2 :(得分:25)

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

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

答案 3 :(得分:13)

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

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

答案 4 :(得分:13)

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

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

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

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

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

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

答案 5 :(得分:9)

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

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

以下是how to implement equals(和hashCode的细节 - 这是它的配对 - 如果你需要实现其中任何一个,你必须实际上始终实现这两者。由于您没有向我们展示客户类,因此很难提供更具体的建议。

正如其他人所说,你最好不要手工使用套装而不是手工完成工作,但即便如此,你仍然需要实施这些方法。

答案 6 :(得分:5)

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

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

当你重写equals()时,你也应该覆盖hashCode(。)。

答案 7 :(得分:5)

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

}

答案 8 :(得分:3)

两个建议:

  • 使用HashSet而不是ArrayList。如果您有一个长列表

  • ,这将大大加快contains()检查
  • 确保Customer.equals()和Customer.hashCode()正确实现,即它们应基于客户对象中基础字段的组合值。

答案 9 :(得分:3)

几乎所有上述答案都是正确的,但我建议在创建相关列表时使用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);

答案 10 :(得分:1)

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

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

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

答案 11 :(得分:1)

最干净的方式是:

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

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

答案 12 :(得分:1)

恕我直言,如何做到这一天最好的方法:

假设您有一个收藏品&#34; dups &#34;并且您想要创建另一个包含相同元素的集合,但删除了所有重复项。下面的单线程就行了。

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

它的工作原理是创建一个Set,根据定义,它不能包含重复项。

基于oracle doc。

答案 13 :(得分:0)

Java的正确答案是使用Set。如果您已经有List<Customer>并想要复制它

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

其他只是直接使用Set实施HashSetTreeSet并跳过List构建阶段。

您需要覆盖Set中放置的域类的hashCode() and equals(),以确保您想要的行为实际上是您所获得的。 equals()可以像比较对象的唯一ID一样简单,就像比较每个字段一样复杂。 hashCode()可以像返回唯一ID“hashCode()表示的StringhashCode()一样简单。

答案 14 :(得分:0)

使用java 8 stream 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);

输出:

在价值观之前:[一,二,二]

价值观之后:[一,二]