[英]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 属性的hascode
和equals
正如其他人所提到的,您可能没有正确实现 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
实现HashSet
, TreeSet
并跳过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.