How to sort a key-value record first by value, then by key in Pascal

1 Answer

0 votes
program SortRecords;

{$mode objfpc}{$H+}

uses
  SysUtils;

type
  TPersonScore = record
    Name  : string;
    Score : Integer;
  end;

  TPersonScoreArray = array of TPersonScore;

{
  Compare two records:
  1. Sort by Score ascending.
  2. If Scores are equal, sort by Name ascending.
  
  Returns:
    < 0 : A comes before B
    = 0 : Equal
    > 0 : A comes after B
}
function ComparePersonScore(const A, B: TPersonScore): Integer;
begin
  if A.Score <> B.Score then
    Exit(A.Score - B.Score);

  Result := CompareText(A.Name, B.Name);
end;

{
  QuickSort implementation using ComparePersonScore.
}
procedure QuickSort(var Arr: TPersonScoreArray; L, R: Integer);
var
  I, J : Integer;
  Pivot, Temp : TPersonScore;
begin
  I := L;
  J := R;
  Pivot := Arr[(L + R) div 2];

  repeat
    while ComparePersonScore(Arr[I], Pivot) < 0 do
      Inc(I);

    while ComparePersonScore(Arr[J], Pivot) > 0 do
      Dec(J);

    if I <= J then
    begin
      Temp := Arr[I];
      Arr[I] := Arr[J];
      Arr[J] := Temp;

      Inc(I);
      Dec(J);
    end;
  until I > J;

  if L < J then
    QuickSort(Arr, L, J);

  if I < R then
    QuickSort(Arr, I, R);
end;

{
  Public sorting function.
}
procedure SortPersonScores(var Arr: TPersonScoreArray);
begin
  if Length(Arr) > 1 then
    QuickSort(Arr, 0, High(Arr));
end;

function CreatePersonScore(const AName: string;
  AScore: Integer): TPersonScore;
begin
  Result.Name := AName;
  Result.Score := AScore;
end;

var
  Data : TPersonScoreArray;
  I    : Integer;
begin
  SetLength(Data, 8);
    
  Data[0] := CreatePersonScore('Luna', 85);
  Data[1] := CreatePersonScore('Sofia', 92);
  Data[2] := CreatePersonScore('Charlie', 96);
  Data[3] := CreatePersonScore('Bella', 92);
  Data[4] := CreatePersonScore('Brock', 80);
  Data[5] := CreatePersonScore('Jolie', 96);
  Data[6] := CreatePersonScore('Bob', 92);
  Data[7] := CreatePersonScore('Eve', 92);

  SortPersonScores(Data);

  for I := 0 to High(Data) do
    Writeln(Data[I].Name:10, '  ', Data[I].Score);
end.


{
run:

     Brock  80
      Luna  85
     Bella  92
       Bob  92
       Eve  92
     Sofia  92
   Charlie  96
     Jolie  96

}

 



answered Oct 23 by avibootz
...