Search code examples
stringdelphi-7

Custom Sort Stringlist


I am an intermediate Delphi programmer that needs to learn a lot so I hope my question here is not to dumb. I have a file with 1546 strings that I need to place in a StringList and do a custom sort. The strings look like this:

2:X,X,2,2,2,X<A>11
7:5,7,7,6,5,5<A>08
3:3,X,0,0,1,0<C/D>11
5:X,2,4,2,5,2<Asus2/Gb>02
3:0,3,2,0,3,0<C/D>02
4:X,0,4,4,0,0<Asus2/Gb>11
4:X,X,4,4,4,2<B>01
3:3,2,1,0,0,3<B#5>11

I need them to look like this:

2:X,X,2,2,2,X<A>11
7:5,7,7,6,5,5<A>08
5:X,2,4,2,5,2<Asus2/Gb>11
4:X,0,4,4,0,0<Asus2/Gb>02
4:X,X,4,4,4,2<B>01
3:3,2,1,0,0,3<B#5>11
3:3,X,0,0,1,0<C/D>11
3:0,3,2,0,3,0<C/D>02

They need to be sorted by the portion of the string between the <...> and the last 2 chars. Any help would be much appreciated.

OK...done, Works quite well. Sorts a list with over 1500 strings in 62ms. Constructive criticism will be appreciated.

function SortChords(List:TStringList; idx1,idx2:integer): integer;
var
s1,s2:string;
begin
    s1:=List[idx1];
    s1:=copy(s1,pos('<',s1)+1,pos('>',s1)-pos('<',s1)-1);
    s2:=List[idx2];
    s2:=copy(s2,pos('<',s2)+1,pos('>',s2)-pos('<',s2)-1);
    if s1 < s2 then
    result:=-1
    else if s1 > s2 then
    result:=1
    else
    result:=0;
end;

Solution

  • You can write your own custom sort procedure and use TStringList.CustomSort to sort in the desired order.

    The following demonstrates using the custom sort. It does not produce the exact output you describe, because you're not clear how you determine the precedence of two items that have the same value between the <> (as in lines 1 and 2, or 3 and 4, of your expected output; you can add code to decide the final order where I've indicated in the code comment. The sample is a complete console application that demonstrates sorting the values you've provided. It's slightly verbose in variable declarations for clarity.

    program Project1;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils, Classes;
    
    function ListSortProc(List: TStringList; Index1, Index2: Integer): Integer;
    var
      StartPosA, EndPosA: Integer;
      StartPosB, EndPosB: Integer;
      TestValA, TestValB: string;
      Comp: Integer;
    begin
      StartPosA := Pos('<', List[Index1]) + 1;
      EndPosA := Pos('>', List[Index1]);
      TestValA := Copy(List[Index1], StartPosA, EndPosA - StartPosA);
      StartPosB := Pos('<', List[Index2]) + 1;
      EndPosB := Pos('>', List[Index2]);
      TestValB := Copy(List[Index2], StartPosB, EndPosB - StartPosB);
      Result := CompareStr(TestValA, TestValB);
      { To do further processing for lines with the same value, add
        code here.
    
       if Result = 0 then
         // Decide on the order of the equal values with whatever
         // criteria you want.
      }
    end;
    
    var
      SL: TStringList;
      s: String;
    
    begin
      SL := TStringList.Create;
      try
        SL.Add('2:X,X,2,2,2,X<A>11');
        SL.Add('7:5,7,7,6,5,5<A>08');
        SL.Add('3:3,X,0,0,1,0<C/D>11');
        SL.Add('5:X,2,4,2,5,2<Asus2/Gb>02');
        SL.Add('3:0,3,2,0,3,0<C/D>02');
        SL.Add('4:X,0,4,4,0,0<Asus2/Gb>11');
        SL.Add('4:X,X,4,4,4,2<B>01');
        SL.Add('3:3,2,1,0,0,3<B#5>11');
        SL.CustomSort(ListSortProc);
        for s in SL do
          WriteLn(s);
        ReadLn;
      finally
        SL.Free;
      end;
    end.
    

    The code above produces this output:

    7:5,7,7,6,5,5<A>08
    2:X,X,2,2,2,X<A>11
    4:X,0,4,4,0,0<Asus2/Gb>11
    5:X,2,4,2,5,2<Asus2/Gb>02
    4:X,X,4,4,4,2<B>01
    3:3,2,1,0,0,3<B#5>11
    3:0,3,2,0,3,0<C/D>02
    3:3,X,0,0,1,0<C/D>11