簡體   English   中英

從Java中刪除ArrayList中的對象

[英]Deleting objects from an ArrayList in Java

如果滿足條件,我需要從ArrayList刪除一些對象,我想知道哪種方式可以更有效。

這是情況:我有一個包含一個包含其他對象的ArrayList的類。 我必須遍歷此ArrayList並刪除滿足特定條件的所有元素。 據我所知,這些將是我刪除的選項:

  1. 創建一個新的ArrayList並添加不符合條件的元素。 在迭代之后,從舊的arraylist交換到沒有元素的新arraylist。

  2. 創建一個新的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秒)並且內存效率會更高,因為我們不需要創建大量的結果來刪除。

希望這有助於某人。

也許Iteratorremove()方法? JDK的默認集合類應該是支持此方法的所有創建者迭代器。

我找到了另一種更快的解決方案:

  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.

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