遍历ArrayList易犯错误
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                遍历ArrayList易犯错误
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                
                            
                            
                            場景:
將ArrayList中符合條件的記錄刪掉,第一時間寫出的程序如下:
????????????foreach?(string?aStr?in??aList)
????????????{
????????????????if?(aStr.Equals(textBox1.Text))
????????????????{
????????????????????aList.Remove(aStr);
????????????????}
????????????}
似乎沒有錯誤,編譯也通過的,但運行時如果真的遇到符合條件的數據,則會拋出錯誤:
簡單的解決辦法是如何呢?這時用Clone方法最好不過了,用如下代碼:
????????????ArrayList?bList?=?(ArrayList)aList.Clone();
????????????foreach?(string?aStr?in??bList)
????????????{
????????????????if?(aStr.Equals(textBox1.Text))
????????????????{
????????????????????aList.Remove(aStr);
????????????????}
????????????}
似乎集合類型都會有這樣的問題的。
posted?on?2004-09-08?13:53?風前絮~~?閱讀(1047)?評論(25)??編輯?收藏?
評論
#?re:?遍歷ArrayList易犯錯誤????
用for就可以避免這樣的問題,而且for的執行效率還高過foreach?
2004-09-08?14:10?|?什么都不知道?
#?re:?遍歷ArrayList易犯錯誤????
啊,你.....你居然...居然敢用foreach來reomove,這是臭名昭著的Collection問題.....?
2004-09-08?14:24?|?寒楓天傷?
#?re:?遍歷ArrayList易犯錯誤????
我一般是用?
foreach(object?item?in?al.ToArray())?
..?
或者是?in?new?ArrayList(somecollection).?
2004-09-08?14:55?|?Lostinet?
#?re:?遍歷ArrayList易犯錯誤????
好象是有一個淺表拷貝的方法。?
最好是用哪個,不要用Clone?
2004-09-08?15:11?|?hyifeng?
#?re:?遍歷ArrayList易犯錯誤????
用for語句反向遍歷即可?
2004-09-08?16:07?|?feilng?
#?re:?遍歷ArrayList易犯錯誤????
我也犯過這樣的錯誤,呵呵?
2004-09-08?16:10?|?cure?
#?re:?遍歷ArrayList易犯錯誤????
To?什么都不知道:
for的方法也可以啊,代碼如下?
????????????for?(int?i=0;i<aList.Count;i++)
????????????????if?(aList[i].Equals(textBox1.Text))
????????????????????aList.RemoveAt(i);
To?Lostinet?:
你的方法也不錯啊
To?hyifeng:
對于ArrayList,Clone已經是一個淺表副本了。你說的是MemberwiseClone嗎?
看來這種處理已經有三種方法了,foreach里面用Clone,for循環,ToArray,不知道那種比較好呢?
如何可以獲得比較的數據?
2004-09-08?16:12?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
To?feilng:?
反向遍歷?有什么好處啊?大致如何實現呢??
2004-09-08?16:18?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
我也有過,for應該是最安全的,而且簡單易懂?
Clone和ToArray至少增加了處理量?
2004-09-08?16:23?|?dali?
#?re:?遍歷ArrayList易犯錯誤????
To?風前絮~~?:?
對于for的代碼,應該增加一個條件分支,調用了RemoveAt方法的話,index不能夠增加。也就是說循環遞增語句不應該寫在for的括號里面。?
2004-09-08?17:56?|?FantasySoft?
#?re:?遍歷ArrayList易犯錯誤????
受不了你們了,竟然。。。。竟然這種低級的錯誤都犯!!!!一個還不要緊,竟然是一群!!!暈~
刪除的代碼如下:
for?(int?i=aList.Count;?--i?>=0;)
????if?(aList[i].Equals(textBox1.Text))
????????aList.RemoveAt(i);
2004-09-08?18:54?|?老翅?
#?re:?遍歷ArrayList易犯錯誤????
呵呵~?
2004-09-08?19:20?|?hBifTs?
#?re:?遍歷ArrayList易犯錯誤????
To?老翅:?
哈哈~~?話也不能這么說了,編程那里會沒有錯誤呢?要不也不會有BUG了。?
感謝你貼的代碼,我試過了,沒有問題,可以說是for的一種方法。?
To?FantasySoft?:?
我那個for的代碼也是通過了的,可以達到效果,請指明我代碼錯誤,感謝!?
2004-09-08?19:58?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
To?風前絮~~?:代碼本身語法沒有錯,只是邏輯上有問題而已。因為RemoveAt方法會改變Count方法的返回值,就造成了不是每個元素都被遍歷到。這也是feilng和老翅提出反向遍歷的原因。?
請看以下代碼:?
using?System.Collections;?
using?System;?
class?Test?
{?
public?static?void?Main()?
{?
ArrayList?test?=?new?ArrayList();?
for(int?i=0;?i?<?3;?i++)?
test.Add("test");?
test.Add("testAgain");?
test.Add("testAgain");?
for(int?i=0;?i?<?test.Count;?i++)?
{?
if?(test[i].Equals("test"))?
test.RemoveAt(i);?
}?
for(int?i?=?0;?i?<?test.Count;i++)?
Console.WriteLine(test[i]);?
}?
}?
test這個ArrayList里面的"test"是不是應該都被remove掉呢?事實上如果這樣寫,還是會剩下一個的。?
2004-09-09?02:22?|?FantasySoft?
#?re:?遍歷ArrayList易犯錯誤????
To?FantasySoft:?
十分感謝!?原來的代碼因為每個不相同的,因此沒有發現這個問題。?
仔細想了下,確實如你所說:?Count變了,使得index=0的被漏掉了。?
看來for的方法只有反向遍歷了。?
有空用ILDASM看了下三種不同方法生成的代碼,比較對應函數,發現用的堆棧最大值一樣,代碼長度不同,for的最短,ToArray()居中,Clone最多。
?
正向for的方法要加個語句就可以了,但看起來比反向臃腫了:
????????????for?(int?i=0;i<aList.Count;i++)
????????????????if?(aList[i].Equals(textBox1.Text))
????????????????{
????????????????????aList.RemoveAt(i);
????????????????????i--;
????????????????}
2004-09-09?09:18?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
To?風前絮~~?:可以這樣寫??????
for?(int?i=0;i<aList.Count;)?
??????if?(aList[i].Equals(textBox1.Text))?
??????{?
?????????????aList.RemoveAt(i);?
??????}?
??????else?
??????????????i++;?
這樣寫是不是就更清晰了呢?for的遞增語句不一定要寫到for的括號里面的。?
2004-09-09?10:24?|?Fantasysoft?
#?re:?遍歷ArrayList易犯錯誤????
對呀,也是個方法!?^_^?
2004-09-09?10:36?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
恕我直言,看到樓主你的“仔細想了下,確實如你所說:Count變了,使得index=0的被漏掉了。”這句話,感覺你并沒有真正理解為什么會產生樓頂的問題?
被遺漏的并不是原list的0號item,而是1號item?
為什么呢?因為當你remove第i個item時,第[i?+?1,?count)域中所有items的索引值皆減一(Array是連續的,要滿足只要有k?∈?[0,?count)則Array[k]必存在),那么當你在循環下一輪用i?+?1為索引訪問的即是原先list中索引為i?+?2的那個item,由此可知,上例中0號被刪除時,原1號變為新0號,原2號變為新1號。。。下一輪訪問的1號就是先前的2號,而原始的1號則永遠沒有被訪問到?
明白了這個自然可以得出正確的迭代方法,正序時需注意索引和可能變化的終止條件,倒序時則簡單些?
2004-09-09?14:44?|?問題男?
#?re:?遍歷ArrayList易犯錯誤????
To?問題男:?
Oh~~?Sorry,估計是我的表達有問題。?
index=0是Count變了后的,它原來的index確實=1,正如你所說的。?
感謝指正!?
2004-09-09?15:16?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
re:?遍歷ArrayList易犯錯誤?
用for語句反向遍歷即可?
2004-09-08?16:07?|?feilng?
完全同意,我覺得這是最好的辦法了?
p.s.這種事情,沒有出過錯的人第一次都會寫錯的,哈哈?
2004-09-09?16:56?|?myrat?
#?re:?遍歷ArrayList易犯錯誤????
看看這段代碼,會有什么結果??
int[]?myarray?=?{1,2,3};?
foreach(int?num?in?myarray){?
????num++;?
}?
2004-09-09?17:21?|?juqiang?
#?re:?遍歷ArrayList易犯錯誤????
To?juqing:
有趣啊
應該是不行的
--------------------------------------------------------------------------------
MSDN中的說明:
foreach?語句為數組或對象集合中的每個元素重復一個嵌入語句組。foreach?語句用于循環訪問集合以獲取所需信息,但不應用于更改集合內容以避免產生不可預知的副作用。
--------------------------------------------------------------------------------
num++?等價于?num?=?num?+?1,修改內容了。
編譯報錯:
...(201):?無法分配到“num”,因為它是只讀的
2004-09-09?17:33?|?風前絮~~?
#?遍歷ArrayList易犯錯誤[TrackBack]????
Ping?Back來自:blog.csdn.net
windsails引用了該文章,地址: http://blog.csdn.net/windsails/archive/2004/09/10/100331.aspx?
2004-09-10?13:21?|?windsails?
#?re:?遍歷ArrayList易犯錯誤????
為什么要反向??
int?i?=0;?
while(?i<aList.Count)?
{?
if?(aList[i].Equals(textBox1.Text))?
{?
aList.RemoveAt(i)?
continue;?
}?
i++;?
}?
2004-10-20?21:29?|?大力水手?
#?re:?遍歷ArrayList易犯錯誤????
反向簡單且效率高啊,aList.Count只在初始化時用一次,其他情況要每次都用啊。雖說aList.Count也是變量,但從機器碼的角度來說,間接地址引用還是要花比寄存器引用多很多的時間的。?
2004-12-09?12:45?|?無名?
                            
                        
                        
                        將ArrayList中符合條件的記錄刪掉,第一時間寫出的程序如下:
????????????foreach?(string?aStr?in??aList)
????????????{
????????????????if?(aStr.Equals(textBox1.Text))
????????????????{
????????????????????aList.Remove(aStr);
????????????????}
????????????}
似乎沒有錯誤,編譯也通過的,但運行時如果真的遇到符合條件的數據,則會拋出錯誤:
簡單的解決辦法是如何呢?這時用Clone方法最好不過了,用如下代碼:
????????????ArrayList?bList?=?(ArrayList)aList.Clone();
????????????foreach?(string?aStr?in??bList)
????????????{
????????????????if?(aStr.Equals(textBox1.Text))
????????????????{
????????????????????aList.Remove(aStr);
????????????????}
????????????}
似乎集合類型都會有這樣的問題的。
posted?on?2004-09-08?13:53?風前絮~~?閱讀(1047)?評論(25)??編輯?收藏?
評論
#?re:?遍歷ArrayList易犯錯誤????
用for就可以避免這樣的問題,而且for的執行效率還高過foreach?
2004-09-08?14:10?|?什么都不知道?
#?re:?遍歷ArrayList易犯錯誤????
啊,你.....你居然...居然敢用foreach來reomove,這是臭名昭著的Collection問題.....?
2004-09-08?14:24?|?寒楓天傷?
#?re:?遍歷ArrayList易犯錯誤????
我一般是用?
foreach(object?item?in?al.ToArray())?
..?
或者是?in?new?ArrayList(somecollection).?
2004-09-08?14:55?|?Lostinet?
#?re:?遍歷ArrayList易犯錯誤????
好象是有一個淺表拷貝的方法。?
最好是用哪個,不要用Clone?
2004-09-08?15:11?|?hyifeng?
#?re:?遍歷ArrayList易犯錯誤????
用for語句反向遍歷即可?
2004-09-08?16:07?|?feilng?
#?re:?遍歷ArrayList易犯錯誤????
我也犯過這樣的錯誤,呵呵?
2004-09-08?16:10?|?cure?
#?re:?遍歷ArrayList易犯錯誤????
To?什么都不知道:
for的方法也可以啊,代碼如下?
????????????for?(int?i=0;i<aList.Count;i++)
????????????????if?(aList[i].Equals(textBox1.Text))
????????????????????aList.RemoveAt(i);
To?Lostinet?:
你的方法也不錯啊
To?hyifeng:
對于ArrayList,Clone已經是一個淺表副本了。你說的是MemberwiseClone嗎?
看來這種處理已經有三種方法了,foreach里面用Clone,for循環,ToArray,不知道那種比較好呢?
如何可以獲得比較的數據?
2004-09-08?16:12?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
To?feilng:?
反向遍歷?有什么好處啊?大致如何實現呢??
2004-09-08?16:18?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
我也有過,for應該是最安全的,而且簡單易懂?
Clone和ToArray至少增加了處理量?
2004-09-08?16:23?|?dali?
#?re:?遍歷ArrayList易犯錯誤????
To?風前絮~~?:?
對于for的代碼,應該增加一個條件分支,調用了RemoveAt方法的話,index不能夠增加。也就是說循環遞增語句不應該寫在for的括號里面。?
2004-09-08?17:56?|?FantasySoft?
#?re:?遍歷ArrayList易犯錯誤????
受不了你們了,竟然。。。。竟然這種低級的錯誤都犯!!!!一個還不要緊,竟然是一群!!!暈~
刪除的代碼如下:
for?(int?i=aList.Count;?--i?>=0;)
????if?(aList[i].Equals(textBox1.Text))
????????aList.RemoveAt(i);
2004-09-08?18:54?|?老翅?
#?re:?遍歷ArrayList易犯錯誤????
呵呵~?
2004-09-08?19:20?|?hBifTs?
#?re:?遍歷ArrayList易犯錯誤????
To?老翅:?
哈哈~~?話也不能這么說了,編程那里會沒有錯誤呢?要不也不會有BUG了。?
感謝你貼的代碼,我試過了,沒有問題,可以說是for的一種方法。?
To?FantasySoft?:?
我那個for的代碼也是通過了的,可以達到效果,請指明我代碼錯誤,感謝!?
2004-09-08?19:58?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
To?風前絮~~?:代碼本身語法沒有錯,只是邏輯上有問題而已。因為RemoveAt方法會改變Count方法的返回值,就造成了不是每個元素都被遍歷到。這也是feilng和老翅提出反向遍歷的原因。?
請看以下代碼:?
using?System.Collections;?
using?System;?
class?Test?
{?
public?static?void?Main()?
{?
ArrayList?test?=?new?ArrayList();?
for(int?i=0;?i?<?3;?i++)?
test.Add("test");?
test.Add("testAgain");?
test.Add("testAgain");?
for(int?i=0;?i?<?test.Count;?i++)?
{?
if?(test[i].Equals("test"))?
test.RemoveAt(i);?
}?
for(int?i?=?0;?i?<?test.Count;i++)?
Console.WriteLine(test[i]);?
}?
}?
test這個ArrayList里面的"test"是不是應該都被remove掉呢?事實上如果這樣寫,還是會剩下一個的。?
2004-09-09?02:22?|?FantasySoft?
#?re:?遍歷ArrayList易犯錯誤????
To?FantasySoft:?
十分感謝!?原來的代碼因為每個不相同的,因此沒有發現這個問題。?
仔細想了下,確實如你所說:?Count變了,使得index=0的被漏掉了。?
看來for的方法只有反向遍歷了。?
有空用ILDASM看了下三種不同方法生成的代碼,比較對應函數,發現用的堆棧最大值一樣,代碼長度不同,for的最短,ToArray()居中,Clone最多。
?
正向for的方法要加個語句就可以了,但看起來比反向臃腫了:
????????????for?(int?i=0;i<aList.Count;i++)
????????????????if?(aList[i].Equals(textBox1.Text))
????????????????{
????????????????????aList.RemoveAt(i);
????????????????????i--;
????????????????}
2004-09-09?09:18?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
To?風前絮~~?:可以這樣寫??????
for?(int?i=0;i<aList.Count;)?
??????if?(aList[i].Equals(textBox1.Text))?
??????{?
?????????????aList.RemoveAt(i);?
??????}?
??????else?
??????????????i++;?
這樣寫是不是就更清晰了呢?for的遞增語句不一定要寫到for的括號里面的。?
2004-09-09?10:24?|?Fantasysoft?
#?re:?遍歷ArrayList易犯錯誤????
對呀,也是個方法!?^_^?
2004-09-09?10:36?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
恕我直言,看到樓主你的“仔細想了下,確實如你所說:Count變了,使得index=0的被漏掉了。”這句話,感覺你并沒有真正理解為什么會產生樓頂的問題?
被遺漏的并不是原list的0號item,而是1號item?
為什么呢?因為當你remove第i個item時,第[i?+?1,?count)域中所有items的索引值皆減一(Array是連續的,要滿足只要有k?∈?[0,?count)則Array[k]必存在),那么當你在循環下一輪用i?+?1為索引訪問的即是原先list中索引為i?+?2的那個item,由此可知,上例中0號被刪除時,原1號變為新0號,原2號變為新1號。。。下一輪訪問的1號就是先前的2號,而原始的1號則永遠沒有被訪問到?
明白了這個自然可以得出正確的迭代方法,正序時需注意索引和可能變化的終止條件,倒序時則簡單些?
2004-09-09?14:44?|?問題男?
#?re:?遍歷ArrayList易犯錯誤????
To?問題男:?
Oh~~?Sorry,估計是我的表達有問題。?
index=0是Count變了后的,它原來的index確實=1,正如你所說的。?
感謝指正!?
2004-09-09?15:16?|?風前絮~~?
#?re:?遍歷ArrayList易犯錯誤????
re:?遍歷ArrayList易犯錯誤?
用for語句反向遍歷即可?
2004-09-08?16:07?|?feilng?
完全同意,我覺得這是最好的辦法了?
p.s.這種事情,沒有出過錯的人第一次都會寫錯的,哈哈?
2004-09-09?16:56?|?myrat?
#?re:?遍歷ArrayList易犯錯誤????
看看這段代碼,會有什么結果??
int[]?myarray?=?{1,2,3};?
foreach(int?num?in?myarray){?
????num++;?
}?
2004-09-09?17:21?|?juqiang?
#?re:?遍歷ArrayList易犯錯誤????
To?juqing:
有趣啊
應該是不行的
--------------------------------------------------------------------------------
MSDN中的說明:
foreach?語句為數組或對象集合中的每個元素重復一個嵌入語句組。foreach?語句用于循環訪問集合以獲取所需信息,但不應用于更改集合內容以避免產生不可預知的副作用。
--------------------------------------------------------------------------------
num++?等價于?num?=?num?+?1,修改內容了。
編譯報錯:
...(201):?無法分配到“num”,因為它是只讀的
2004-09-09?17:33?|?風前絮~~?
#?遍歷ArrayList易犯錯誤[TrackBack]????
Ping?Back來自:blog.csdn.net
windsails引用了該文章,地址: http://blog.csdn.net/windsails/archive/2004/09/10/100331.aspx?
2004-09-10?13:21?|?windsails?
#?re:?遍歷ArrayList易犯錯誤????
為什么要反向??
int?i?=0;?
while(?i<aList.Count)?
{?
if?(aList[i].Equals(textBox1.Text))?
{?
aList.RemoveAt(i)?
continue;?
}?
i++;?
}?
2004-10-20?21:29?|?大力水手?
#?re:?遍歷ArrayList易犯錯誤????
反向簡單且效率高啊,aList.Count只在初始化時用一次,其他情況要每次都用啊。雖說aList.Count也是變量,但從機器碼的角度來說,間接地址引用還是要花比寄存器引用多很多的時間的。?
2004-12-09?12:45?|?無名?
總結
以上是生活随笔為你收集整理的遍历ArrayList易犯错误的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: python从random生成列表_Py
- 下一篇: python生成随机码_python生成
