[英]Remove elements from an Arraylist if they are present in another one without raising ConcurrentModificationException
[英]Best way to remove one arraylist elements from another arraylist
Java(7,8)中用於消除一個Arraylist
integer
元素的最佳性能方法是什么? 所有元素在第一和第二列表中都是唯一的。
目前我知道API方法removeall
並以這種方式使用它:
tempList.removeAll(tempList2);
當我操作arraylists有超過10000個元素時出現問題。 例如,當我刪除65000個元素時,延遲似乎約為2秒。 但我需要使用超過1000000個元素的更大的列表進行操作。
這個問題的策略是什么?
也許新的Stream API應該解決它?
TL;博士:
把事情簡單化。 使用
list.removeAll(new HashSet<T>(listOfElementsToRemove));
代替。
正如Eran在他的回答中已經提到的那樣:低性能源於通用removeAll
實現的偽代碼是
public boolean removeAll(Collection<?> c) {
for (each element e of this) {
if (c.contains(e)) {
this.remove(e);
}
}
}
因此,要刪除的元素列表上執行的contains
調用將導致O(n * k)性能(其中n
是要刪除的元素數, k
是列表中調用該方法的元素數)上)。
天真,一個可以想像的是, this.remove(e)
上的呼叫List
還可能有O(K),實施這一項目也將有二次的復雜性。 但事實並非如此:您提到列表是特定的ArrayList
實例。 和ArrayList#removeAll
方法被實現為委托給調用方法batchRemove
直接操作底層陣列上,並且不會單獨刪除的元素。
因此,您所要做的就是確保包含要刪除的元素的集合中的查找很快 - 最好是O(1)。 這可以通過將這些元素放入Set
來實現。 最后,它可以寫成
list.removeAll(new HashSet<T>(listOfElementsToRemove));
附注:
Eran的回答有恕我直言的兩個主要缺點:首先,它需要對列表進行排序 ,即O(n * logn) - 並且根本不需要。 但更重要的是(顯然): 排序可能會改變元素的順序! 如果根本不需要怎么辦?
遠程相關: removeAll
實現中還涉及其他一些細微之處。 例如,在某些情況下, HashSet removeAll方法的速度非常慢 。 雖然當要刪除的元素存儲在列表中時,這也歸結為O(n * n),但在這種特定情況下,確切的行為可能確實令人驚訝。
好吧,因為removeAll
檢查tempList
每個元素是否出現在tempList2
,運行時間與第一個列表的大小成比例乘以第二個列表的大小,這意味着O(N^2)
除非其中一個列表非常小,可以被視為“常量”。
另一方面,如果您對列表進行預排序,然后通過單次迭代迭代兩個列表(類似於合並排序中的合並步驟),則排序將采用O(NlogN)
和迭代O(N)
,給你一個總的運行時間O(NlogN)
。 這里N
是兩個列表中較大者的大小。
如果您可以通過排序結構替換列表(可能是TreeSet
,因為您說元素是唯一的),您可以在線性時間內實現removeAll
,因為您不必進行任何排序。
我還沒有測試它,但是這樣的東西可以工作(假設tempList
和tempList2
都被排序):
Iterator<Integer> iter1 = tempList.iterator();
Iterator<Integer> iter2 = tempList2.iterator();
Integer current = null;
Integer current2 = null;
boolean advance = true;
while (iter1.hasNext() && iter2.hasNext()) {
if (advance) {
current = iter1.next();
advance = false;
}
if (current2 == null || current > current2) {
current2 = iter2.next();
}
if (current <= current2) {
advance = true;
if (current == current2)
iter1.remove();
}
}
我懷疑從ArrayList中刪除是一個性能命中,因為當刪除中間的元素時,列表可能被分割,或者如果在刪除元素后必須壓縮列表。 這樣做可能會更快:
這應該有O(N)
; 如果創建Set並且其中的查找被假定為常量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.