2017-12-14 56 views
6

Tôi biết cách loại bỏ các chuỗi trùng lặp khỏi một TStringList bằng cách sử dụng dupignore cho một Tstringlist được sắp xếp.Xóa các dòng trùng lặp khỏi TStringList mà không cần phân loại trong Delphi

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

Nhưng trong chuỗi trường hợp của tôi không được sắp xếp.

Sử dụng vòng lặp FOR tìm bản trùng lặp rất chậm (cũng sử dụng indexOF()) khi TStringList có hàng trăm nghìn dòng.

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; 

có cách nào tốt hơn không?

Trả lời

6

Đây là cách tôi sẽ tiếp cận vấn đề này:

  1. Tạo một từ điển keyed trên một chuỗi. Không quan trọng là loại giá trị.
  2. Lặp lại qua danh sách chuỗi theo thứ tự ngược lại.
  3. Đối với mỗi chuỗi, hãy kiểm tra xem nó có nằm trong từ điển hay không.
  4. Nếu nó có trong từ điển, hãy xóa khỏi danh sách chuỗi. Nếu không, hãy thêm vào từ điển.

Nếu có một số lượng lớn các từ khóa trùng lặp cần xóa thì hiệu suất của những điều trên sẽ bị ảnh hưởng bởi việc loại bỏ lặp lại khỏi danh sách chuỗi. Đó là bởi vì mỗi mục sẽ bị xóa kết quả trong các mục sau sẽ bị dịch chuyển xuống một chỉ mục. Bạn có thể tránh điều này bằng cách sao chép vào danh sách mới thay vì xóa tại chỗ.

Ngoài ra, bạn có thể hoạt động ở vị trí như thế này:

  1. Tạo một từ điển keyed trên một chuỗi. Không quan trọng là loại giá trị.
  2. Khởi tạo biến có tên Count bằng không.
  3. Lặp lại qua danh sách chuỗi theo thứ tự chuyển tiếp.
  4. Đối với mỗi chuỗi, hãy kiểm tra xem nó có nằm trong từ điển hay không.
  5. Nếu nó có trong từ điển, không phải làm gì cả. Nếu không, hãy thêm vào từ điển, sao chép vào chỉ mục Count của danh sách và sau đó tăng Count.
  6. Khi quá trình lặp hoàn tất, hãy đổi kích thước danh sách thành các phần tử Count.

Điểm của từ điển là tra cứu là hoạt động O (1) và do đó thuật toán thứ hai có độ phức tạp thời gian O (n).

+0

Cảm ơn rất nhiều. Nó nhanh hơn những người khác. –

2

Tôi sẽ sử dụng thủ thuật, bằng cách sắp xếp và danh sách chưa được phân loại. Như thế này:

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. 

Tôi muốn theo dõi các số dòng (i) và gán nó với chuỗi bằng cách đúc như một đối tượng; sắp xếp danh sách và loại bỏ các bản sao như trước, nhưng sau đó bỏ phân loại nó bằng cách sử dụng một sắp xếp tùy chỉnh trên các đối tượng.

+1

'Thử nghiệm' nằm sai vị trí ở đây.Nó phải được ngay sau khi tài nguyên được bảo vệ đã được cấp phát. Ví dụ, nếu tập tin không tồn tại thì mã của bạn sẽ đưa ra một ngoại lệ trong 'TStreamReader.create' và sau đó gọi' f.Free' trong đó 'f' chưa được khởi tạo. –

Các vấn đề liên quan