:)
首先,我的代码
procedure TForm1.Button3Click(Sender: TObject);
var tempId,i:integer;
begin
tempId:=strtoint(edit5.Text);
plik:=TStringList.Create;
plik.LoadFromFile('.\klienci\'+linia_klient[id+1]+'.txt');
if (plik.Count=1) then
begin
label6.Caption:='then';
if (tempId=StrToInt(plik[0])) then
begin
Label6.Caption:='Zwrócono';
plik.Delete(0);
end
end
else
for i:=0 to plik.Count-2 do
begin
if (tempId=StrToInt(plik[i])) then
begin
Label6.Caption:='Zwrócono';
plik.Delete(i);
end;
end;
plik.SaveToFile('.\klienci\'+linia_klient[id+1]+'.txt');
plik.Free;
end;
for i:=0 to plik.Count-2 do
我可以删除任何元素但不能删除
最后。for i:=0 to plik.Count-1 do
我可以删除任何元素时没有
但从头到尾。因为否则列表索引超出范围。会发生什么事?如何安全搜索并从TStringList中删除元素?
答案 0 :(得分:8)
从列表中删除intems时,要使用downto
循环,即
for i := plik.Count-1 downto 0 do
begin
if (tempId=StrToInt(plik[i])) then
begin
Label6.Caption:='Zwrócono';
plik.Delete(i);
end;
end;
这确保了如果删除项目,当您从列表的列表末尾开始移动列表时,循环索引将保持有效。
答案 1 :(得分:5)
这是一个经典问题。 for
循环在循环开始时对循环边界进行一次计算,因此您可以在结束时运行,这将解释索引超出范围的错误。
但是,即使for
循环每次像while
那样评估循环边界,也不会真正有用。删除元素时,将Count
减1并将其余元素向下移动到列表中的一个元素。因此,您可以更改所有仍处理元素的索引。
标准技巧是循环列表:
for i := List.Count-1 downto 0 do
if DeleteThisItem(i) then
List.Delete(i);
以这种方式编写时,对Delete
的调用会影响已经处理过的元素的索引。
答案 2 :(得分:2)
For I := stringlist.count-1 downto 0 do
现在您可以删除所有项目而不会出现任何错误
答案 3 :(得分:2)
在像for i:=1 to count
这样的升序循环中,您无法删除正在迭代的列表中的项目。
根据您想要实现的整体逻辑,有几种解决方案。
您可以将for
循环更改为重新评估while
的{{1}}循环,并且不会在删除迭代中增加索引
你可以改变循环,有点count
而不是for i:=count downto 1
,您可以创建一个临时列表,只复制您要保留的项目,然后重新复制。
答案 4 :(得分:2)
正如其他人所说,使用downto
循环通常是最佳选择。当然,它确实改变了循环的语义,因此它向后运行而不是向前运行。如果要继续向前循环,则必须使用while
循环,例如:
I := 0;
while I < plik.Count do
begin
if (tempId = StrToInt(plik[I])) then
begin
...
plik.Delete(I);
end else
Inc(I);
end;
或者:
var
CurIdx, Cnt: Integer;
CurIdx := 0;
Cnt := plik.Count;
for I := 0 to Cnt-1 do
begin
if (tempId = StrToInt(plik[CurIdx])) then
begin
...
plik.Delete(CurIdx);
end else
Inc(CurIdx);
end;