對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++初級階段模板實現的連結串列或者雙向連結串列更加的方便,更加方便的遍歷,方便查詢,方便各種操作。