簡體   English   中英

是否從 ArrayList 或 LinkedList 中刪除元素,同時在 Java 中使用 for 循環遍歷它不好? 如果是這樣,為什么?

[英]Is removing elements from an ArrayList or LinkedList while iterating through it with a for loop in Java bad? If so, why?

我正在向某人展示我的代碼,他們說這會導致未定義的行為。 作為一名 Java 程序員,這不是我理解的。 在下面的代碼塊中,我將遍歷scenes ,這是一個 ArrayList,並從中刪除元素。

for(int i = 0; i < scenes.size() - 1; i++)
    {
        if(!(Double.valueOf(scenes.get(i + 1)) - Double.valueOf(scenes.get(i)) > 10))
        {
            scenes.remove(i + 1);
            i--;
        }
    }

這會編譯並且不會在運行時引發異常,但我仍然不確定它是否是編程禁忌,為什么它是編程禁忌,以及正確的方法是什么。 我聽說過使用Iterator.remove()以及創建一個全新的List

ArrayList中,從列表中間刪除一個元素需要您將所有具有較高索引的元素向下移動一個。 如果您執行一次(或少量),這很好,但如果您重復執行,則效率低下。

您也不想為此使用Iterator ,因為Iterator.remove()也遇到了同樣的問題。

更好的方法是通過列表 go ,將要保留的元素移動到新位置; 然后在最后刪除列表的尾部:

int dst = 0;
for (int src = 0; src < scenes.size(); ++dst) {
  // You want to keep this element.
  scenes.set(dst, scenes.get(src++));

  // Now walk along the list until you find the element you want to keep.
  while (src < scenes.size()
         && Double.parseDouble(scenes.get(src)) - Double.parseDouble(scenes.get(dst)) <= 10) {
    // Increment the src pointer, so you won't keep the element.
    ++src;
  }
}

// Remove the tail of the list in one go.
scenes.subList(dst, scenes.size()).clear();

(這種“移位和清除”方法是ArrayList.removeIf使用的方法;您不能在此處直接使用它,因為您無法檢查列表中的相鄰元素,您只能訪問當前元素)。


您可以采用類似的方法,該方法也可以有效地處理諸如LinkedList之類的非隨機訪問列表。 您需要避免重復調用getset ,因為在LinkedList的情況下這些是O(size)

在這種情況下,您將使用ListIterator而不是普通索引:

ListIterator<String> dst = scenes.listIterator();
for (ListIterator<String> src = scenes.listIterator(); src.hasNext();) {
  dst.next();
  String curr = src.next();
  dst.set(curr);

  while (src.hasNext()
         && Double.parseDouble(src.next()) - Double.parseDouble(curr) <= 10) {}
}
scenes.subList(dst.nextIndex(), scenes.size()).clear();

或者類似的東西。 我沒有測試過它,而且ListIterator使用起來總是很混亂。

這很簡單,適用於 ArrayList 或 LinkedList:

        Iterator<String> iterator = list.iterator();
        double current = 0;
        double next;
        boolean firstTime = true;
        while (iterator.hasNext()) {
            if (firstTime) {
                current = Double.parseDouble(iterator.next());
                firstTime = false;
            } else {
                next = Double.parseDouble(iterator.next());
                if (next - current > 10) {
                    current = next;
                } else {
                    iterator.remove();
                }
            }
        }

暫無
暫無

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

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