簡體   English   中英

從另一個arraylist中刪除一個arraylist元素的最佳方法

[英]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 ,因為您不必進行任何排序。

我還沒有測試它,但是這樣的東西可以工作(假設tempListtempList2都被排序):

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中刪除是一個性能命中,因為當刪除中間的元素時,列表可能被分割,或者如果在刪除元素后必須壓縮列表。 這樣做可能會更快:

  1. 創建要刪除的元素的“Set”
  2. 創建一個你需要的新結果ArrayList,稱之為R.你可以在構造時給它足夠的大小。
  3. 通過原始列表迭代,您需要刪除它中的元素,如果在Set中找到該元素,請不要將其添加到R,否則添加它。

這應該有O(N) ; 如果創建Set並且其中的查找被假定為常量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM