1

:)

首先,我的代码

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我可以从头到尾删除任何元素时。因为否则List index out of bounds

怎么回事?如何从 TStringList 中安全搜索和删除元素?

4

5 回答 5

8

从列表中删除要使用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;

这确保如果您删除项目,循环索引在您从列表末尾向列表开头移动时保持有效。

于 2011-12-13T11:24:15.900 回答
5

这是一个经典的问题。循环在for循环开始时对循环边界进行一次评估,因此您运行结束,这解释了您的索引超出范围错误。

但是,即使for循环每次都像 awhile那样评估循环边界,这也无济于事。当您删除一个元素时,您将减少Count1 并将剩余元素在列表中向下移动一个。因此,您更改了所有仍需处理的元素的索引。

标准技巧是循环列表:

for i := List.Count-1 downto 0 do
  if DeleteThisItem(i) then
    List.Delete(i);

当您以这种方式编写时,调用会Delete影响已处理的元素的索引

于 2011-12-13T11:25:28.347 回答
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; 
于 2011-12-13T19:18:57.277 回答
2

在一个升序循环中,就像for i:=1 to count您不能删除您正在迭代的列表中的项目一样。

根据您想要实现的整体逻辑,有几种解决方案。

  1. 您可以将for循环更改为while重新评估count并且不增加删除迭代中的索引的循环

  2. 你可以反转循环,有点for i:=count downto 1

  3. 而不是delete,您可以创建一个临时列表并仅将要保留的项目复制到那里,然后将其重新复制回来。

于 2011-12-13T11:31:10.683 回答
2
For I := stringlist.count-1 downto 0 do

现在您可以删除所有项目而不会出现任何错误

于 2011-12-13T11:25:40.783 回答