1. 程式人生 > >對List元素迭代刪除的注意事項以及三個方法

對List元素迭代刪除的注意事項以及三個方法

有一個List,裡面儲存1-100000的數,,寫出幾種刪除是偶數的元素的程式碼
第一印象是找到list中偶數,對其直接刪除

for(int num:list){
            if(num%2==0) list.remove(num);
        }

結果就報了concurrentModificationException,併發修改異常
我們都知道,使用for迴圈遍歷集合,內部會走Iterator,即判斷hasNext之後,使用next移動游標到下一個。
看了一下hasNext與next的原始碼

private class Itr implements Iterator<E
> {
int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size;//遊標不等於元素個數就是還有下一個 } public E next() { checkForComodification();//check是否併發修改
int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } final
void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }

**modCount是集合新增元素、刪除元素的次數,expectedModCount是預期的修改次數。
每次進入next都會判斷modCount與expectedModCount是否相等,不相等則丟擲併發修改異常**
可以想到,假設起始在list新增100000資料,則modCount為100000,expectedModCount也初始為100000,然而對list直接remove一次之後,刪除元素次數就+1了,那麼expectedModCount=100001!=modCount,所以報錯

而使用Iterator刪除元素就不會報錯了,比如

方法一:

Iterator<Integer> it = list.iterator();
        while(it.hasNext()){
            int i=it.next();
            if(i%2==0) it.remove();
        }

花費600ms
使用it.remove()來刪除每一個符合的元素,Iterator會自動修改expectedModCount,使modCount與之相等。

方法二:
先找到符合的元素組成集合,在一次性removeAll

List<Integer> list3 = new ArrayList<>();
        for(int num:list){
            if(num%2==0){
                list3.add(num);
            }
        }
list.removeAll(list3);

十萬條資料花費3000ms+

看到畫了3000ms,我面紅耳赤,這tm,腦子有問題了,這又是寫新集合又是刪原集合,還是個ArrayList而不是LinkedList,怎麼可能更快,

於是
方法三:
。。。。。突然發現上面程式碼的list3反過來不就是結果嘛。

List<Integer> list2 = new ArrayList<Integer>();
        while(it.hasNext()){
            int i=it.next();
            if(i%2!=0) list2.add(i);
        }

這裡的list2就是“刪完”偶數的list
耗時10ms

相關推薦

List元素刪除注意事項以及方法

有一個List,裡面儲存1-100000的數,,寫出幾種刪除是偶數的元素的程式碼 第一印象是找到list中偶數,對其直接刪除 for(int num:list){ if(num%2==0) list.remove(num);

vector中使用注意事項

1.使用iter++;和++iter;兩種方式遍歷的次數是相同的,但在STL中效率不同。前++返回引用,後++返回一個臨時物件,因為iterator是類模板,使用 iter++這種形式要返回一個無用的臨時物件,而it++是函式過載,所以編譯器無法對其進行優化,所以每遍歷一個

Iterator 注意事項(1)

迭代器在使用時,如果在迴圈內迭代,每迴圈一次迭代,不能iterator.next多次,使用多次就相當於迭代多次。 eg : 錯誤的: public static void main(String[] args) { HashMap<String, String&

vector容器,器,空間介面卡方法的實現

C++的STL庫有一個容器叫vector,這個容器底層的資料結構是一個記憶體可以自動增長的陣列,每次當陣列儲存滿了以後,記憶體可以自動增加兩倍,請完成vector容器、迭代器和空間配置器三個類方法的實現。 #include<iostream> using namespace

用遞迴,,通項公式方法實現斐波那契數列求解

斐波那契數列指的是這樣一個數列:1、1、2、3、5、8、13、21、……    這個數列從第三項開始,每一項都等於前兩項之和。它的通項公式為:(1/√5)*{[(1+√5)/2]^n -[(1-√5)/2]^n}(又叫“比內公式”,是用無理數表示有理數的一個範例。)(√5表

【Python】List一邊一邊刪除的安全方法

最簡單的例子nums = [1,2,3] i = 0 while i < len(nums): del nums[i] print(nums)雖然,不推薦在迭代的過程中不能進行增刪操作,但在一些要求額外空間複雜度為O(1)的題目(例如:LeetCode 26)中

泛型程式設計學習,編寫一個類似STL庫中的簡易list器(iterator)

泛型程式設計學習,編寫一個類似STL庫中的簡易list的迭代器(iterator) 前言 近期在研究stl原始碼及stl裡各種實現的細節,初學入門免不了模仿,以下便寫一次自己的簡單的list容器的迭代器。 首先,在開始編寫List的迭代器的時候我們首先應該瞭解我們要寫的List和其迭

list器能解決併發問題,collection 的器不能解決併發問題,for可以解決併發問題

list的迭代器能解決併發問題,collection 的迭代器不能解決併發問題   為什麼list支援add,collection不支援   例如有兩個人同時新增第三個元素 list的迭代器能鎖定執行緒 只有等第一人新增完成才能進行第二個人新增 而 collection的迭代器卻不

STL------List器的實現

1. List   List是STL庫(標準模板庫)中的一個容器。它的實質上就是一個雙向帶頭迴圈連結串列,這樣的設計有以下幾個優點:    隨機插入資料時,不用遍歷連結串列,去找某一特定位置 尾插時,只需head->prev就

15 API-集合(Collection(功能,器),List(List特有器,併發異常),常見資料結構圖示(棧,佇列,陣列,連結串列))&物件陣列

1:物件陣列(掌握) (1)陣列既可以儲存基本資料型別,也可以儲存引用型別。它儲存引用型別的時候的陣列就叫物件陣列。 (2)案例:用陣列儲存5個學生物件,並遍歷陣列。 學生的物件 public class Student { // 成員變數 private Stri

Python 可變物件和注意

記住,在迭代可變物件的時候修改它們並不是個好主意. 這在迭代器出現之前就是一個問題. 一個流行的例子就是迴圈列表的時候刪除滿足(或不滿足)特定條件的項:for eachURL in allURLs: if not eachURL.startswith('http:/

list 元素按某個屬性進行排序

public class Test { public static void main(String[] args) { List<Student> list = new ArrayList<Stu

中文進行MD5加密的注意事項(Java版)

       在工作中需要和第三方進行Http通訊,在通訊內容中有幾個引數涉及到了中文。自己在進行MD5加密驗證過程中,遇到了一些很奇怪(本人認為MD5是一個通用簡單的加密演算法,應該很穩定很完美了吧!)的問題: 問題1:接收到的問題亂碼了 解決:這個問題很常見,網上有很多

程式中資料庫的操作歷史和資料庫操作的實體類注意事項

稍微瞭解一下程式中資料庫操作歷史吧! 1.首先是JDBC連線 2.c3p0 3.JPA JPA是Java Persistence API的簡稱,中文名Java持久層API,是JDK 5.0註解或XML描述物件-關係表的對映關係,並將執行期的實體物件持久化到資料庫中. 4.hibernate &nb

產品快速需要注意

    產品的快速迭代,先確實階段性時間,再考慮功能點。    在做產品時,要考慮下一個產品版本的時間什麼時候出,然後列出所有的需求的功能點,對所有需求做一個優先順序排序,確認在當前時間下面,能完成哪些需求。有點不緊急的需求可以放到下一個版本中。    生活不易,請微笑對待你

Python 檔案內容 按位元組處理

def process(string): print 'Processing: ',string f=open(r'D:\\ruanjian\\Python\\程式\\1.txt') while True: char=f.read(1) if not

python 給定可集合統計出現頻率,並排序

給定一個可迭代sequence,對其中的值進行出現次數統計: 方法1: def get_counts(sequence): counts = {} for x in sequence

權重初始化方式神經網路次數的影響

做一個網路 輸入X範圍是[1e-16,37] 權重初始化方式 Random rand1 =new Random(); int ti1=rand1.nextInt(98)+1; tw[a][b]=(double)ti1/n;  學習率0.1 本文用於檢測當

關於使用ES6語法實現物件的

使用[Symbol.iterator]實現迭代 備註:此處的操作,由於使用的方法是Object.keys(object)的方式獲取到物件的屬性。 所以遍歷所使用的 鍵(keys()),值(values()),和鍵值對(entries())方法,均採用Symb

C++模擬實現容器list(含器)

list同之前實現過的容器vector類似,都是STL眾多容器中的一個。STL中實現的連結串列是帶頭結點的雙向迴圈連結串列,這種連結串列相比於之前我們在C語言和C++初級階段模板實現的連結串列或者雙向連結串列更加的方便,更加方便的遍歷,方便查詢,方便各種操作。