Delphi Tips(8) TStringListのDeleteについて
TStringListで特定のStringsを削除するケースはよくあると思うのだが、
for文で回して、IF文で特定のStringsをDeleteしようとすると、インデックスが範囲を超えてしまう。
原因はDeleteした瞬間に、インデックスがづれてしまうためなのだが...
どうすればいいのか少々ハマったのでメモっておきます
◆Delete処理 誤り(インデックスの範囲を超える)
処理:A,B,Cの文字をStringListに入れて、Bだけ削除する
procedure TForm2.Button1Click(Sender: TObject); var SL: TStringList; I: Integer; begin SL := TStringList.Create; SL.add('A'); SL.add('B'); SL.add('C'); for I := 0 to SL.Count - 1 do if SL.Strings[I] = 'B' then SL.Delete(I); showmessage(IntToStr(SL.cout)); end;
for文中ではIの変数は操作できない...
シンプルで良い方法はないか考えたが、下記のように修正することにした。
◆Delete処理 修正版
処理:A,B,Cの文字をStringListに入れて、Bだけ削除する
procedure TForm2.Button1Click(Sender: TObject); var SL, SL2: TStringList; // SL2追加 I: Integer; begin SL := TStringList.Create; SL2 := TStringList.Create; // SL2追加 SL.add('A'); SL.add('B'); SL.add('C'); for I := 0 to SL.Count - 1 do if SL.Strings[I] <> 'B' then SL2.add(SL.Strings[I]); // SL2.ADD に変更 SL := SL2; // SL2をSLにコピーする showmessage(IntToStr(SL.cout)); SL2.free; end;
Values、Namesが面白かったので、ついでに記載しておきます
Valuesを使うと、多次元の配列が表現できます。
上記のDeleteサンプルのようにValuesを使った場合の、削除方法です。
◆Values版のDelete処理
処理:大石、石川、斉藤の住所を登録し、石川のみ削除する
procedure TForm2.Button1Click(Sender: TObject); var SL1, SL2, SL3: TStringList; I: Integer; begin SL1 := TStringList.Create; SL2 := TStringList.Create; SL3 := TStringList.Create; SL1.values['名前'] := '大石'; SL1.values['住所'] := '島田'; SL2.values['大石'] := SL1.Text; SL1.values['名前'] := '石川'; SL1.values['住所'] := '島田'; SL2.values['石川'] := SL1.Text; SL1.values['名前'] := '斉藤'; SL1.values['住所'] := '島田'; SL2.values['斉藤'] := SL1.Text; for I := 0 to SL2.Count - 1 do if SL2.Names[I] <> '石川' then SL3.values[SL2.Names[I]] := SL2.values[SL2.Names[I]]; SL2 := SL3; for I := 0 to SL2.Count - 1 do showmessage(SL2.values[SL2.Names[I]]); SL1.free; SL3.free; end;
TStringsの派生クラスで要素を削除するときはfor i := SL.Count – 1 downto 0 doのように逆方向から処理をする、という手をよく使います。
うわ!その手がありましたか。気付かなかったです。
今度試してみます。コメントありがとうございました。