2011-06-08 112 views
5

我需要過濾一個ArrayList並刪除找到的元素。對於Java相對較新,我想知道最有效的方法是實現這個目標(因爲它在移動設備上運行)。目前我這樣做:Java:高效的ArrayList過濾?

// We display only top-level dealers (parentId=-10) 
ArrayList<DealerProductCount> subDealers = new ArrayList<DealerProductCount>(); 
for (DealerProductCount dealer : wsResponse.Dealers) { 
    if (dealer.ParentId != -10) subDealers.add(dealer); 
} 
wsResponse.Dealers.removeAll(subDealers); 

它可以做到沒有臨時對象?也許通過直接操作(刪除)迭代列表中的元素?

+1

還有其他數據結構的項目刪除更有效。從LinkedList中刪除將具有O(n)性能。從HashMap中刪除將具有恆定的時間性能。 – 2011-06-08 15:40:33

回答

16

有效地除去了一些從ArrayList元件需要一些想法。天真的做法是這樣的:

Iterator<DealerProductCount> it = wsResponse.Dealers.iterator(); 
while (it.hasNext()) { 
    if (it.next().ParentId != -10) { 
     it.remove(); 
    } 
} 

問題是,每次你刪除一個元素,你複製(平均)一半的其餘元素。這是因爲從ArrayList中刪除元素需要複製元素之後的所有元素,將其向左移動一個位置。

涉及要刪除的元素列表的原始解決方案基本上會執行相同的操作。不幸的是,ArrayList的屬性不允許removeAll比上述做得更好。

如果你希望刪除一些元素,下面是更有效:

ArrayList<DealerProductCount> retain = 
     new ArrayList<DealerProductCount>(wsResponse.Dealers.size()); 
for (DealerProductCount dealer : wsResponse.Dealers) { 
    if (dealer.ParentId == -10) { 
     retain.add(dealer); 
    } 
} 
// either assign 'retain' to 'wsResponse.Dealers' or ... 
wsResponse.Dealers.clear(); 
wsResponse.Dealers.addAll(retain); 

我們正在複製(幾乎)整個列表兩次,所以這應該收支平衡(平均),如果你刪除少至4個元素。


有趣的是,函數式編程語言/庫支持過濾方法,並且可以在列表中執行此任務;即更有效得多。我認爲,如果/當Java支持lambdas時,我們可以期望有重大的改進,並且增強了收集API以使用它們。

+0

謝謝Stephen,爲您提供極好的深入解釋!所以回家的信息是填充一個新的ArrayList通常比從現有的元素中移除元素更好。很高興知道! – Bachi 2011-06-12 00:04:44

7

如果您使用迭代器,則可以在迭代時刪除安全元素。

+1

(如果迭代器提供了刪除的實現 - 它可能會拋出一個UnsupportedOperationException異常 - 所以這隻適用於你非常瞭解你的迭代器的情況) – 2011-06-08 14:58:10

4

的一種方法將使用迭代器,而不是爲每個:

Iterator<DealerProductCount> iter = wsResponse.Dealers.iterator() 
while(iter.hasNext()) { 
    if (iter.next().ParentId != -10) iter.remove(); 
}