[英]Deleting objects from an ArrayList in Java
如果滿足條件,我需要從ArrayList
刪除一些對象,我想知道哪種方式可以更有效。
這是情況:我有一個包含一個包含其他對象的ArrayList
的類。 我必須遍歷此ArrayList
並刪除滿足特定條件的所有元素。 據我所知,這些將是我刪除的選項:
創建一個新的ArrayList
並添加不符合條件的元素。 在迭代之后,從舊的arraylist交換到沒有元素的新arraylist。
創建一個新的ArrayList
並添加滿足條件的元素。 在迭代之后,使用removeAll()
方法將ArrayList
與要刪除的對象一起傳遞。
有沒有更有效的方法從ArrayList
刪除對象?
您可以向后迭代並在瀏覽ArrayList時刪除。 這具有后續元素不需要移位的優點,並且比向前移動更容易編程。
另一種方式:Iterator有一個可選的remove()方法,它是為ArrayList實現的。 您可以在迭代時使用它。
我不知道,哪種變體是最高效的,你應該測量它。
starblue評論說,復雜性並不好,這也是真的(對於removeAll()),因為ArrayList必須復制所有元素,如果在中間是添加或刪除的元素。 對於那種情況,LinkedList應該更好。 但是,因為我們都不知道您的真實用例,所以最好的方法是測量所有變體,以選擇最佳解決方案。
我想,大多數高性能用戶都會使用listIterator
方法進行反向迭代:
for (ListIterator<E> iter = list.listIterator(list.size()); iter.hasPrevious();){
if (weWantToDelete(iter.previous())) iter.remove();
}
編輯:很久以后,人們可能還想添加Java 8方法,使用lambda或方法引用從列表(或任何集合!) 中刪除元素 。 如果您願意,可以使用集合的就地filter
:
list.removeIf(e -> e.isBad() && e.shouldGoAway());
這可能是清理集合的最佳方法。 由於它使用內部迭代,因此集合實現可以采用快捷方式使其盡可能快(對於ArrayList
,它可以最小化所需的復制量)。
顯然,在你提到的兩種方法中,數字1更有效率,因為它只需要遍歷列表一次,而使用方法編號2,列表必須遍歷兩次(首先找到要刪除的元素,然后它們到刪除它們)。
實際上,從另一個列表中刪除元素列表可能是一個比O(n)更差的算法,因此方法2更糟糕。
迭代器方法:
List data = ...;
for (Iterator i = data.iterator(); i.hasNext(); ) {
Object element = i.next();
if (!(...)) {
i.remove();
}
}
首先,我確保這確實是一個性能瓶頸,否則我會選擇最干凈,最具表現力的解決方案。
如果它是性能瓶頸,只需嘗試不同的策略,看看哪個是最快的。 我的賭注是創建一個新的ArrayList並將所需的對象放在那個中,丟棄舊的ArrayList。
除非你肯定你所面臨的問題確實是一個瓶頸,否則我會追求可讀性
public ArrayList filterThings() {
ArrayList pileOfThings;
ArrayList filteredPileOfThings = new ArrayList();
for (Thing thingy : pileOfThings) {
if (thingy.property != 1) {
filteredPileOfThings.add(thingy);
}
}
return filteredPileOfThings;
}
從ArrayList中刪除元素有隱藏的成本。 每次刪除元素時,都需要移動元素以填充“洞”。 平均而言,這將為具有N個元素的列表進行N / 2
分配。
因此,從N元素ArrayList中移除M個元素平均為O(M * N)
。 O(N)解決方案涉及創建新列表。 例如。
List data = ...;
List newData = new ArrayList(data.size());
for (Iterator i = data.iterator(); i.hasNext(); ) {
Object element = i.next();
if ((...)) {
newData.add(element);
}
}
如果N很大,我的猜測是這種方法比remove
方法更快,因為M的值小到3或4。
但重要的是創建newList
大的newList
來保存list
所有元素,以避免在展開時復制后備數組。
int sizepuede= listaoptionVO.size();
for (int i = 0; i < sizepuede; i++) {
if(listaoptionVO.get(i).getDescripcionRuc()==null){
listaoptionVO.remove(listaoptionVO.get(i));
i--;
sizepuede--;
}
}
編輯:添加縮進
使用迭代器,您可以始終處理按順序排列的元素,而不是指定的索引。 所以,你不應該對上述問題感到困擾。
Iterator itr = list.iterator();
String strElement = "";
while(itr.hasNext()){
strElement = (String)itr.next();
if(strElement.equals("2"))
{
itr.remove();
}
雖然這是違反直覺的,但這是我大量加快這項操作的方式。
正是我在做什么:
ArrayList < HashMap < String , String >> results; // This has been filled with a whole bunch of results
ArrayList <HashMap <String,String >> discard = findResultsToDiscard(results);
results.removeall(丟棄);
然而,刪除所有方法花費了超過6秒(不包括獲得丟棄結果的方法)從2000(ish)的數組中刪除大約800個結果。
我嘗試了gustafc和其他人在這篇文章中提出的迭代器方法。
這確實加快了操作速度(降至約4秒)但是這仍然不夠好。 所以我嘗試了一些冒險的東西......
ArrayList < HashMap < String, String>> results;
List < Integer > noIndex = getTheDiscardedIndexs(results);
for (int j = noIndex.size()-1; j >= 0; j-- ){
results.remove(noIndex.get(j).intValue());
}
而getTheDiscardedIndexs保存一個索引數組,而不是一個HashMaps數組。 事實證明,加速移除對象的速度要快得多(現在大約0.1秒)並且內存效率會更高,因為我們不需要創建大量的結果來刪除。
希望這有助於某人。
我找到了另一種更快的解決方案:
int j = 0;
for (Iterator i = list.listIterator(); i.hasNext(); ) {
j++;
if (campo.getNome().equals(key)) {
i.remove();
i = list.listIterator(j);
}
}
我很擅長Mnementh的推薦。
只是一個警告,但
ConcurrentModificationException
請注意,您沒有運行多個線程。 如果執行多個線程,並且線程未完全同步,則可能出現此異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.