2014-07-21 61 views
3

我想了解Delphi中的泛型,但是TList有一個非常基本的問題。如何在使用for-in循環迭代時更新TList?

我已經成功創建了一個列表整數並填充了1000個奇數。我想改變列表中每個可以被3整除的數字。我認爲我可以做這樣的事情。

For I in Mylist Do 
Begin 
    If (I mod 3)= 0 Then 
    I:=0; 
End; 

這顯然不起作用,所以我會很感激有人解釋什麼會。

+0

這是Delphi語言非常薄弱的​​一個領域。其他語言具有強大的迭代器,允許您對集合進行變異。 –

+1

我想知道Embarcadero需要多少工作才能讓枚舉器的'Current'屬性被讀/寫而不是隻讀。 –

+0

可能的重複項http://stackoverflow.com/q/1105519/960757,http://stackoverflow.com/q/2246087/960757。 – TLama

回答

4

你的代碼不會工作,因爲你試圖修改循環中的循環控制變量(I),這是不允許的。它告訴你的是,在編譯器錯誤:

[dcc32 Error] Project1.dpr(23): E2081 Assignment to FOR-Loop variable 'i' 

如果要修改的列表中,您需要通過列表迭代老式的方式(通過索引)來代替。

for i := 0 to List.Count - 1 do 
    if (List[i] mod 3) = 0 then 
    List[i] := 0; 
+1

是的,但我會加上:「如果你想修改列表,你需要用老式的方式迭代列表(通過索引)而不是枚舉器(請注意Delphi的集合中沒有迭代器)。「 –

+0

@Rudy有迭代器。他們只是作爲統計員被錯誤地命名。 –

+0

@Rudy:我同意我應該用「修改列表」加以澄清。儘管如此,[文檔](http://docwiki.embarcadero.com/RADStudio/XE6/en/Declarations_and_Statements#Iteration_Over_Containers_Using_For_statements)指的是'forin'作爲迭代而不是枚舉。我在某種程度上改寫了這個句子。 –

0
uses 
    System.Generics.Collections; 

procedure TForm1.BitBtn1Click(Sender: TObject); 
var 
    _List: TList<integer>; 
    i: integer; 
begin 
    _List := TList<integer>.Create; 
    try 

    // Add few odd numbers 
    for i := 0 to 100 do 
    begin 
     if (i mod 2) <> 0 then 
     _List.Add(i); 
    end; 

    // Replace numbers with 0 that divides by 3 
    for i := 0 to _List.Count - 1 do 
    begin 
     if (_List[i] mod 3) = 0 then 
     _List[i] := 0; 
    end; 

    // Show new list 
    for i := 0 to _List.Count - 1 do 
     OutputDebugstring(PWideChar(IntToStr(_List[i]))); 

    finally 
    FreeAndNil(_List); 
    end; 
end; 

你不重複自己改變(如我),你想改變值(例如_List [1])

+0

_List是一個局部變量,不能從其他地方訪問。你爲什麼要FreeAndNil呢? –

+0

它有什麼不對? –

+1

我沒有說這是錯的。我只是問你爲什麼這樣做。該變量處於其範圍的最後,並且無法從其他任何地方訪問,所以我想知道爲什麼使用'FreeAndNil'而不是'.Free'。 –

6

您使用的是for..in循環,它採用的是隻讀的枚舉。此代碼:

For I in Mylist Do 
Begin 
    If (I mod 3) = 0 Then 
    I := 0; 
End; 

實際上是這樣做的:

Enum := Mylist.GetEnumerator; 
while Enum.MoveNext do 
Begin 
    I := Enum.Current; 
    If (I mod 3) = 0 Then 
    I := 0; 
End; 

這就是爲什麼你不能修改在for..in循環列表內容。你必須使用一個老式的for循環,而不是使用TList<T>.Items[]屬性來訪問值:

For I := 0 to Mylist.Count-1 Do 
Begin 
    If (Mylist[I] mod 3) = 0 Then 
    Mylist[I] := 0; 
End; 

更新:到然後取出零,你可以這樣做:

For I := Mylist.Count-1 downto 0 Do 
Begin 
    If Mylist[I] = 0 Then 
    Mylist.Delete(I); 
End; 

或者,在初始循環中執行以便不需要第二個循環:

For I := Mylist.Count-1 downto 0 Do 
Begin 
    If (Mylist[I] mod 3) = 0 Then 
    Mylist.Delete(I); 
End; 
+0

非常感謝 - 這非常有幫助,我已成功修改了我的代碼。但是,這又提出了另一個問題。我將如何去除列表中現在爲零的所有項目? (當然,有效縮短名單)。 – user3861642

+0

你將不得不循環遍歷列表(向後)第二次尋找零。我用例子更新了我的答案。 –