Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Sort a Delphi TStringList name/value pairs as integers

Tags:

sorting

delphi

I have a TStringList of Name/Value pairs. The names are all integer values 9stored as strings of course) and the values are all strings (comma separated).

e.g.

5016=Catch the Fish!,honeyman,0
30686=Ozarktree1 Goes to town,ozarktreel,0

. . .

I would like to call the add routine and add new lines in the TStringlist, but need a way to sort the list afterwards.

e.g.

Tags.Add(frmTag.edtTagNo.Text + '=' +
         frmTag.edtTitle.Text + ',' +
         frmTag.edtCreator.Text + ',' +
         IntToStr(ord(frmTag.cbxOwned.Checked)));
Tags.Sort;

Here is what I tried:

Tags:= TStringList.Create;
 Tags.CustomSort(StringListSortComparefn);
 Tags.Sorted:= True;

my custom sort routine:

function StringListSortComparefn(List: TStringList; Index1, Index2: Integer): Integer;
var
 i1, i2 : Integer;
begin
 i1 := StrToIntDef(List.Names[Index1], 0);
 i2 := StrToIntDef(List.Names[Index2], 0);
 Result:= CompareValue(i1, i2);
end;

However, it still seems to be sorting them like strings instead of integers.

I even tried creating my own class:

type
 TXStringList = class(TStringList)
 procedure Sort;override;
end;

implementation

function StringListSortComparefn(List: TStringList; Index1, Index2: Integer): Integer;
var
i1, i2 : Integer;
begin
i1 := StrToIntDef(List.Names[Index1], 0);
i2 := StrToIntDef(List.Names[Index2], 0);
Result:= CompareValue(i1, i2);
end;

procedure TXStringList.Sort;
begin
 CustomSort(StringListSortComparefn);
end;

I even tried some examples on SO (e.g. Sorting TSTringList Names property as integers instead of strings)

Can someone tell me what I am doing wrong? Everytime, the list gets sorted as strings and not as integers.

30686=Ozarktree1 Goes to town,ozarktreel,0
5016=Catch the Fish!,honeyman,0
like image 353
JakeSays Avatar asked Apr 02 '14 13:04

JakeSays


1 Answers

You can do a simple integer subtraction:

function StringListSortComparefn(List: TStringList; Index1, Index2: Integer): Integer;
var
 i1, i2 : Integer;
begin
 i1 := StrToIntDef(List.Names[Index1], 0);
 i2 := StrToIntDef(List.Names[Index2], 0);
 Result := i1 - i2
end;

To reverse the sort order, simply reverse the operands in the subtraction:

Result := i2 - i1;

Here's a quick, compiilable console example:

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;

function StringListSortProc(List: TStringList; Index1, Index2: Integer): Integer;
var
  i1, i2: Integer;
begin
  i1 := StrToIntDef(List.Names[Index1], -1);
  i2 := StrToIntDef(List.Names[Index2], -1);
  Result := i1 - i2;
end;

var
  SL: TStringList;
  s: string;
begin
  SL := TStringList.Create;
  SL.Add('3456=Line 1');
  SL.Add('345=Line 2');
  SL.Add('123=Line 3');
  SL.Add('59231=Line 4');
  SL.Add('545=Line 5');
  WriteLn('Before sort');
  for s in SL do
    WriteLn(#32#32 + s);
  SL.CustomSort(StringListSortProc);
  WriteLn('');
  WriteLn('After sort');
  for s in SL do
    WriteLn(#32#32 + s);
  ReadLn;
  SL.Free;
end.

And the resulting output:

Before sort
  3456=Line 1
  345=Line 2
  123=Line 3
  59231=Line 4
  545=Line 5

After sort
  123=Line 3
  345=Line 2
  545=Line 5
  3456=Line 1
  59231=Line 4
like image 51
Ken White Avatar answered Sep 22 '22 19:09

Ken White