在Java中删除数组中重复项的最佳方法是什么?
我有一个对象数组需要删除/过滤重复项。 我只是在Object元素上覆盖equals&hachCode,然后将它们粘贴在Set中……但我认为我至少应该轮询stackoverflow以查看是否有其他方法,或许是其他一些API的一些聪明的方法?
我同意你的方法来覆盖hashCode()
和equals()
并使用实现Set
东西。
这样做也使任何其他开发人员都清楚地知道需要非重复的特性。
另一个原因 – 您现在可以选择最符合您需求的实施方案:
- HashSet的
- TreeSet中
- LinkedHashSet
并且您不必更改代码以在将来更改实施。
我在网上发现了这个
以下两种方法允许您删除ArrayList中的重复项。 removeDuplicate不维护removeDuplicateWithOrder维护订单的顺序,其中包含一些性能开销。
-
removeDuplicate方法:
/** List order not maintained **/ public static void removeDuplicate(ArrayList arlList) { HashSet h = new HashSet(arlList); arlList.clear(); arlList.addAll(h); }
-
removeDuplicateWithOrder方法:
/** List order maintained **/ public static void removeDuplicateWithOrder(ArrayList arlList) { Set set = new HashSet(); List newList = new ArrayList(); for (Iterator iter = arlList.iterator(); iter.hasNext();) { Object element = iter.next(); if (set.add(element)) newList.add(element); } arlList.clear(); arlList.addAll(newList); }
覆盖equals
和hashCode
并创建一个集合也是我的第一个想法。 在inheritance层次结构中,无论如何都要对这些方法进行一些重写,这是一种很好的做法。
我认为如果你使用LinkedHashSet
你甚至会保留独特元素的顺序……
基本上,您需要一个LinkedHashSet
实现,它支持List
接口以进行随机访问。 因此,这就是你需要的:
public class LinkedHashSetList
extends LinkedHashSet implements List {
// Implementations for List
methods here ...
}
List
方法的实现将访问和操作底层的LinkedHashSet
。 当一个人试图通过List
添加方法添加重复项时(抛出exception或在不同的索引处重新添加项目)将是选项:你可以选择其中一个或者make可由class级用户配置)。
使用List distinctList
在第一次iterator
偶然发现时记录元素,返回distinctList作为列表删除所有重复项
private List removeDups(List list){ 设置tempSet = new HashSet(); 列出distinctList = new ArrayList(); for(Iterator it = list.iterator(); it.hasNext();){ Object next = it.next(); if(tempSet.add(next)){ distinctList.add(下); } } return distinctList; }
我想重申杰森在评论中提出的观点:
为什么要把自己放在那一点上?
为什么要将数组用于不应该重复的数据结构?
使用Set
或SortedSet
(当元素也具有自然顺序时)始终保持元素。 如果您需要保持插入顺序,那么您可以使用已指出的LinkedHashSet
。
必须对一些数据结构进行后处理通常是一种暗示,你应该选择一个不同的数据结构。
当然,最初的post提出了一个问题:“你是如何获得那个arrays(可能包含重复的条目)?”
你是否需要将数组(带有重复数据)用于其他目的,或者你可以从一开始就使用Set?
或者,如果您需要知道每个值的出现次数,可以使用Map
来跟踪计数。 此外,Multimap类的Google Collections定义可能有用。
Set
绝对是您最好的选择。 从数组中删除东西(不创建新数组)的唯一方法是将它们清空,然后最后进行大量的空检查。
从通用编程标准来看,您可以始终双重枚举集合,然后比较源和目标。
如果你的内部枚举总是在源之后开始一个条目,那么它是相当有效的(伪代码可以遵循)
foreach ( array as source ) { // keep track where we are in the array place++; // loop the array starting at the entry AFTER the current one we are comparing to for ( i=place+1; i < max(array); i++ ) { if ( source === array[place] ) { destroy(array[i]); } } }
你可以说可以加一个rest时间; 在破坏之后的声明,但是你只发现了第一个重复,但如果这是你将拥有的所有,那么这将是一个不错的小优化。