排序 TStringlist 并保留原始索引

Sorting TStringlist and retaining original index

我有一个关于 Delphi StringLists 和排序的问题。我正在对属性列表(具有重复条目)进行排序,因此我需要在排序之前保留它们的原始索引。这是我正在尝试的示例

procedure TestFind;
var
  i, iIndex :integer;
  slStrings : TStringlist;
begin
    slStrings := TStringList.Create;   
    slStrings.Sorted := False;

    slStrings.Add('Zebra');
    slStrings.AddObject('Zebra',TObject(1));   
    slStrings.Add('Bat');
    slStrings.AddObject('Bat',TObject(2));
    slStrings.Add('Cat');
    slStrings.AddObject('Cat',TObject(3));
    slStrings.Add('Hat');
    slStrings.AddObject('Hat',TObject(4));
    slStrings.Add('Aat');
    slStrings.AddObject('Aat',TObject(5));      

    slStrings.sorted := True;   

    if slStrings.Find('Zebra',iIndex) then
    begin  
      while slStrings.Strings[iIndex] = slStrings.Strings[iIndex + 1] do
      begin
        i := ObjectToInt(slStrings.Objects[iIndex]) ;     
        AddMemoData ('Stringlist Found at Position: ' + inttoStr(i) + ' Current index position is: ' + inttoStr(iIndex), false); 
        inc(iIndex);
      end;    

      i := ObjectToInt(slStrings.Objects[iIndex]) ;     
      AddMemoData ('Stringlist Found at Position: ' + inttoStr(i) + ' Current index position is: ' + inttoStr(iIndex), false); 

    end;

end;

当我 运行 得到 Zebra 的值 0,8 时,这对我来说毫无意义,我希望得到 1,4

的消息

我真的搞不懂你的代码试图实现什么,但它正在访问列表末尾之外的内容。为避免您的 while 测试可以像这样修改:

while (iIndex<slStrings.Count-1) 
  and (slStrings.Strings[iIndex] = slStrings.Strings[iIndex + 1]) do

您对 Objects[] 的使用将有效。对列表进行排序时,放置在那里的值将与其匹配的 Strings[] 值保持一致。

但是,如果我是您,我不会使用字符串列表来完成此任务。我会这样声明一条记录:

TMyRec = record
  Name: string;
  Index: Integer;
end;

我会将它们保存在 TList<TMyRec> 中,然后使用自定义比较器对它们进行排序。

我注意到您添加了每个对象两次,一次带有关联索引,一次没有。后面的那些实例将获得默认索引值 0。我还观察到,由于我发现的越界错误,您提供的代码将不会执行。此外,即使您修复它也不会提供您声明的形式的输出。

换句话说,您发布的代码似乎与您 运行 的代码有很大不同。我已经根据您在问题中包含的代码进行了回答。我希望您能在此基础上接受答案,不要指望对您拥有的我们看不到的代码提供帮助。也许我应该投票结束。

总之,主要问题可能出在这里:

slStrings.Add('Zebra');
slStrings.AddObject('Zebra',TObject(1));   
slStrings.Add('Bat');
slStrings.AddObject('Bat',TObject(2));
slStrings.Add('Cat');
slStrings.AddObject('Cat',TObject(3));
slStrings.Add('Hat');
slStrings.AddObject('Hat',TObject(4));
slStrings.Add('Aat');
slStrings.AddObject('Aat',TObject(5));      

这相当于:

slStrings.AddObject('Zebra',TObject(0));   
slStrings.AddObject('Zebra',TObject(1));   
slStrings.AddObject('Bat',TObject(0));
slStrings.AddObject('Bat',TObject(2));
slStrings.AddObject('Cat',TObject(0));
slStrings.AddObject('Cat',TObject(3));
slStrings.AddObject('Hat',TObject(0));
slStrings.AddObject('Hat',TObject(4));
slStrings.AddObject('Aat',TObject(0));      
slStrings.AddObject('Aat',TObject(5));      

你真的想写这个吗:

slStrings.AddObject('Zebra',TObject(1));   
slStrings.AddObject('Bat',TObject(2));
slStrings.AddObject('Cat',TObject(3));
slStrings.AddObject('Hat',TObject(4));
slStrings.AddObject('Aat',TObject(5));      

解决方案是这样的:

procedure TestFind;
    var
    i, iIndex, iStringSize :integer;
    slStrings : TStringlist;
    begin
        slStrings := TStringList.Create;   
        slStrings.Sorted := False;

        slStrings.AddObject('Zebra',TObject(1));   
        slStrings.AddObject('Bat',TObject(2));
        slStrings.AddObject('Cat',TObject(3));
        slStrings.AddObject('Hat',TObject(4));
        slStrings.AddObject('Zebra',TObject(6));
        slStrings.AddObject('Aat',TObject(5)); 
        slStrings.AddObject('Zebra',TObject(7));     

        slStrings.sorted := True;   


        if slStrings.Find('Bat',iIndex) then
        begin  
          //find lowest position of string matching found string 
          while iIndex > 0 do
           begin
             if (g_slVials.Strings[iIndex] = g_slVials.Strings[iIndex-1]) then
               iIndex := iIndex - 1 
             else 
               break; 
           end;

          iStringSize := slStrings.Count;
          while iIndex < iStringSize -1 do  //check for more matching strings in higher range
          begin
            if (g_slVials.Strings[iIndex] = g_slVials.Strings[iIndex+1]) then  
            begin
              i := ObjectToInt(slStrings.Objects[iIndex]) ;     
              AddMemoData ('Stringlist Found at Position: ' + inttoStr(i) + ' Current index position is: ' + inttoStr(iIndex), false); 
              inc(iIndex);   
            end else
              break;
          end;    

          i := ObjectToInt(slStrings.Objects[iIndex]) ;     
          AddMemoData ('Stringlist Found at Position: ' + inttoStr(i) + ' Current index position is: ' + inttoStr(iIndex), false); 

        end;

    end;

这让我可以找到所有匹配的字符串和return它们的索引位置