从TStringList中删除重复行而不在Delphi中进行排序

时间:2017-12-14 16:47:46

标签: delphi

我知道如何使用dupignore从TStringList中删除重复的字符串以用于排序的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;

还有更好的方法吗?

3 个答案:

答案 0 :(得分:6)

以下是我将如何处理此问题:

  1. 创建一个键入字符串的字典。值类型是无关紧要的。
  2. 以相反的顺序遍历字符串列表。
  3. 对于每个字符串,检查它是否在字典中。
  4. 如果它在字典中,请从字符串列表中删除。否则添加到字典中。
  5. 如果要删除大量重复项,则从字符串列表中重复删除会影响上述性能。这是因为要删除的每个项目都会导致后面的项目向下移动一个索引。您可以通过复制到新列表而不是删除就地来避免这种情况。

    或者,你可以这样操作:

    1. 创建一个键入字符串的字典。值类型是无关紧要的。
    2. 将名为Count的变量初始化为零。
    3. 按正向顺序遍历字符串列表。
    4. 对于每个字符串,检查它是否在字典中。
    5. 如果它在字典中,则什么也不做。否则添加到字典中,复制到列表的索引Count,然后递增Count
    6. 迭代完成后,将列表大小调整为Count个元素。
    7. 字典的要点是查找是O(1)操作,因此第二种算法具有O(n)时间复杂度。

答案 1 :(得分:2)

我会使用trickery,通过排序和未排序的列表。像这样:

for row in try! db.prepare("SELECT * FROM things") {
  let value = row[4]

  print(value) //This logs "Optional(7)" or "Optional(1.2)" etc.

  switch value{

    case let double as Double:
      print("Double: \(double)") //This never gets called...

    case let int as Int:
      print("Int: \(int)") //This never gets called

    default:
      return 0 //This always gets called
  }
}

答案 2 :(得分: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)并通过强制转换为对象来为其分配;按照以前的方式对列表进行排序并删除重复项,然后使用对象的自定义排序对其进行取消排序。