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

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

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

如果该代码不起作用,则可能没有适当地在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以便两个相等的Customer对象将返回相同的散列值。 上面定义equals匹配hashCode是:

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

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

假设你想保持当前的顺序,并不想要一个Set ,也许最简单的是:

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

如果你想改变原始列表:

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

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

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

注意:如果你要覆盖equals()不要忘记重写hashCode() equals() ! 否则,你可能会遇到你的HashMap和其他数据结构的问题。 为了很好的理解这是为什么,以及避免什么隐患,可以考虑查看关于equals()hashCode() Josh Bloch的Effective Java章节(该链接仅包含关于为什么在实现equals()时必须实现hashCode() equals() ,但是如何覆盖equals()也有很好的覆盖)。

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

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

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

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

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

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

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

我怀疑你可能没有正确实现Customer.equals() )。

List.contains()使用equals()来validation它的任何元素是否与作为parameter passing的对象相同。 但是, equalstesting物理标识的默认实现,而不是值标识。 所以如果你没有在Customer覆盖它,它将返回两个具有相同状态的不同Customer对象的false。

下面是如何实现equals (和hashCode ,这是它的配对 – 如果你需要实现其中的任何一个,你几乎总是要实现这两者)的基本细节。 由于您没有向我们展示客户类,因此很难提供更具体的build议。

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

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

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

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

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

两点build议:

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

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

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

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

不过,你也应该注意到这个代码被认为是非常低效的,因为运行时可能是元素平方的数量。

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

最干净的方法是:

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

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

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

假设你有一个集合“ dups ”,你想创build另一个集合包含相同的元素,但所有重复消除。 下面的一行就是这个技巧。

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

它通过创build一个Set,根据定义,它不能包含重复项。

基于oracle doc。

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

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

别的只是直接使用Set实现HashSetTreeSet并跳过List构造阶段。

您将需要重写置于Set中的域类的hashCode()equals() ,以确保实际获得的行为。 equals()可以像比较对象的唯一标识符一样简单,比如比较每个字段。 hashCode()可以像返回唯一标识符“ String representation”或“ hashCode()hashCode()

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

输出:

在值之前:[one,one,two]

之后值:[一,二]

 Class removeduplicates { public static void main(string args[[]) { int I; for(int =0;i'<10;I++) { system.out.println(+i); if([]I=[j]) { system.out.println(1,2,3,1,1,1,2,2,2) } } } }