2017-12-14 77 views
6

ソートされたTstringlistにdupignoreを使用して、TStringListから重複する文字列を削除する方法を知っています。DelphiでソートせずにTStringListから重複する行を削除する

CallData := TStringList.Create; 
CallData.Sorted := True; 
Call.Duplicates := dupIgnore; 

しかし、私の場合は、文字列はをソートしてはいけません。

TStringListに何十万行もある場合、FORループを使用すると重複を見つけるのが非常に遅くなります(indexOF()も使用します)。

if OpenDialog1.Execute then 
    begin 
    Try 
     y := TStringList.create; 
     f := TStreamReader.create(OpenDialog1.FileName, TEncoding.UTF8, True); 
     while not f.EndOfStream do 
     begin 
     l := f.ReadLine; 
     X.Add(l); 
     end; 

     g := Tstreamwriter.create('d:\logX.txt', True, TEncoding.UTF8); 
     for I := 0 to X.count - 1 do 
     begin 


      if y.IndexOf(X[I]) = -1 then 

      y.Add(X[I]); 

     end; 

     for j := 0 to y.count - 1 do 
     g.WriteLine(y[j]); 

    Finally 
     f.free; 
     y.free; 
     g.free; 
    End; 
    end; 

もっと良い方法がありますか?ここで

答えて

6

は、私はこの問題にアプローチする方法をです:

  1. は、文字列をキーと辞書を作成します。値の型は問題ではありません。
  2. 逆順で文字列リストを反復処理します。
  3. 各文字列について、その文字列が辞書に含まれているかどうかを確認します。
  4. 辞書に含まれている場合は、文字列リストから削除します。それ以外の場合は辞書に追加します。

削除する重複数が多い場合、上記のパフォーマンスは、文字列リストからの繰り返しの削除の影響を受けます。削除される各アイテムは、後のアイテムが1つのインデックスにシフトされるためです。これは、インプレースを削除するのではなく、新しいリストにコピーすることで回避できます。

また、あなたがこのような場所で動作することができます。

  1. 文字列をキーと辞書を作成します。値の型は問題ではありません。
  2. Countという名前の変数を0に初期化します。
  3. 文字列リストを順方向に反復処理します。
  4. 各文字列について、その文字列が辞書に含まれているかどうかを確認します。
  5. 辞書にある場合は何もしないでください。それ以外の場合は、ディクショナリに追加し、リストのインデックスCountにコピーし、次にCountを増やします。
  6. 繰り返しが完了したら、リストのサイズをCountの要素に変更します。

検索のポイントはO(1)操作であるため、2番目のアルゴリズムはO(n)時間の複雑さがあります。

+0

ありがとうございました。他のものよりも速いです。 –

2

私はトリッキーを使用しますが、ソートされたリストとソートされていないリストがあります。このように:

y := TStringList.create; 
    s := TStringList.create; 
    s.Sorted := TRUE; 
    s.Duplicates := dupIgnore; 

    f := TStreamReader.create(OpenDialog1.FileName, TEncoding.UTF8, True); 
    while not f.EndOfStream do 
    begin 
    l := f.ReadLine; 
    s.Add(l); 
    if s.Count > y.Count then y.Add(l); 
    end; 

    // etc. 
1
function compareobjects 
      (list  : Tstringlist; 
      index1 : integer; 
      index2 : integer 
     )   : integer; 
begin 
    if index1 = index2 then 
    result := 0 
    else 
    if integer(list.objects[index1]) < integer(list.objects[index2]) then 
     result := -1 
    else 
     result := 1; 
end; 

begin 
    Try 
    y := TStringList.create; 
    y.Sorted := true; 
    y.Duplicates := dupignore; 
    f := TStreamReader.create('c:\106x\q47780823.bat'); 
    i := 0; 
    while not f.EndOfStream do 
    begin 
     inc(i); 
     line := f.readline; 
     y.Addobject(line,tobject(i)); 
    end; 
    y.Sorted := false; 
    y.CustomSort(compareobjects); 

    for i := 0 to y.count - 1 do 
     WriteLn(y[i]); 

    Finally 
     f.free; 
     y.free; 
    End; 
    readln; 
end. 

私は行番号(i)を追跡し、オブジェクトとしてキャストすることにより、文字列とそれを割り当てると思います。以前と同じようにリストをソートして重複を削除しますが、オブジェクトのカスタムソートを使用してソートを解除します。

+1

「試行」が間違った場所にあります。保護されたリソースが割り当てられた直後でなければなりません。たとえば、ファイルが存在しない場合、コードは 'TStreamReader.create'で例外を発生させ、' f.Free'を呼び出します。ここで 'f'は初期化されていません。 –