对TStringlist进行排序并保留原始索引

时间:2016-02-04 11:39:11

标签: sorting delphi delphi-xe2 tstringlist

我有一个关于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的消息

2 个答案:

答案 0 :(得分:2)

我真的无法弄清楚你的代码试图实现什么,但是它正在超出列表的末尾进行访问。为避免可以像这样修改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));      

答案 1 :(得分:-1)

解决方案就是:

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;

这允许我找到所有匹配的字符串并返回它们的索引位置