排序 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它们的索引位置
我有一个关于 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它们的索引位置