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端から端までを除いて要素を削除できる場合。それ以外の場合は、インデックスが範囲外になります

何が起こっているの?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ループは、ループの開始時にループの境界を1回評価するため、終了を実行すると、インデックスの範囲外エラーが説明されます。

しかし、forループが毎回ループ境界を評価したとしても、whileそれは実際には役に立ちません。要素を削除すると、Countbyが1つ減り、残りの要素がリスト内で1つ下に移動します。したがって、まだ処理されていない要素すべてのインデックスを変更します。

標準的なトリックは、リストをループダウンすることです。

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

このように記述すると、toの呼び出しは、すでにDelete処理されている要素のインデックスに影響を与えます。

于 2011-12-13T11:25:28.347 に答える
2
For I := stringlist.count-1 downto 0 do

これで、エラーなしですべてのアイテムを削除できます

于 2011-12-13T11:25:40.783 に答える
2

for i:=1 to count繰り返しているリストの項目を削除できないような昇順のループで。

達成したいことの全体的なロジックに応じて、いくつかの解決策があります。

  1. ループを、削除の反復でインデックスを再評価してインクリメントしないforループに変更できます。whilecount

  2. ループを逆にすることができます、ちょっとfor i:=count downto 1

  3. の代わりにdelete、一時的なリストを作成し、そこに保持したいアイテムだけをコピーして、それを再コピーすることができます。

于 2011-12-13T11:31:10.683 に答える
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 に答える