如何从列表中删除重复项?
我想从列表中删除重复项,但是我所做的是不工作的:
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的对象相同。 但是, equals
testing物理标识的默认实现,而不是值标识。 所以如果你没有在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));
并覆盖hascode
并equals
每个实体的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
实现HashSet
, TreeSet
并跳过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) } } } }