Sorting Array of records with multiple sort keys

I need a function that will sort an array of records, using multiple keys, i.e. similar to using
ORDER BY customer_no, Inv_date, ord_number in SQL.

The number of records in the array will not be very large, probably only several hundred maximum.

Any guidance will be greatly appreciated.

Alan
LVL 1
alanjbrownAsked:
Who is Participating?
 
kretzschmarConnect With a Mentor Commented:
well, a sample

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    fList : TList;
    procedure DisplayList;
  public
    { Public declarations }
  end;

  PToOrderRec = ^TToOrderRec;
  TToOrderRec = record
                  customerName : String[100];
                  Customer_no  : Integer;
                  Inv_Date : TDateTime;
                  OrderNo  : Integer;
                end;


var
  Form1: TForm1;

implementation

{$R *.dfm}

function RandomStr(ALen : Integer) : String;
var i : integer;
begin
  result := '';
  for i := 1 to ALen do
    result := result + chr(random(26)+65);
end;

function RandomInt(Range : Integer) : Integer;
begin
  result := Random(Range);
end;


//sort Customer_no, Inv_Date, OrderNo
function CustomSort(p1,p2 : pointer) : Integer;
var pa, pb : PToOrderRec;  //just to read it better
begin
  pa := PToOrderRec(p1);
  pb := PToOrderRec(p2);
  result := 0;
  if      pa^.Customer_no > pb^.Customer_no then
    result := 1
  else if pa^.Customer_no < pb^.Customer_no then
    result := -1
  else if pa^.Inv_Date > pb^.Inv_Date then
    result := 1
  else if pa^.Inv_Date < pb^.Inv_Date then
    result := -1
  else if pa^.OrderNo > pb^.OrderNo then
    result := 1
  else if pa^.OrderNo < pb^.OrderNo then
    result := -1
  else
    result := 0;
end;

procedure TForm1.DisplayList;
var
  i : integer;
  s : string;
begin
  for i := 0 to flist.Count-1 do
  begin
    s :=     PToOrderRec(fList[i])^.customerName + ' - ';
    s := s + IntToStr(PToOrderRec(fList[i])^.Customer_no) + ' - ';
    s := s + DateToStr(PToOrderRec(fList[i])^.Inv_Date) + ' - ';
    s := s + IntToStr(PToOrderRec(fList[i])^.Orderno);
    memo1.Lines.Add(s);
  end;
  memo1.Lines.Add('<---------------------------------------------->');
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  i : integer;
  p : PToOrderRec;
begin
  //simulate record
  for i := 1 to 100 do
  begin
    new(p);
    p^.customerName := RandomStr(25);
    p^.Customer_no := RandomInt(999999);
    p^.Inv_Date := RandomInt(trunc(now));
    p^.OrderNo := RandomInt(999999);
    fList.Add(p);
  end;
  //Output unsorted
  DisplayList;
  //sort
  flist.Sort(CustomSort);
  //Output sorted
  DisplayList;
  //free memory
  for i := 0 to flist.Count-1 do
    dispose(PToOrderRec(flist[i]));
  flist.Clear;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  flist := TList.Create;
end;


procedure TForm1.FormDestroy(Sender: TObject);
begin
  flist.Free;
end;

end.

just ask if somewhat unclear

meikl ;-)
0
 
kretzschmarCommented:
you may use a tlist or tstringlist as your record-container,
rather than an array, then u can use the customsort capability
of this objects.

just ask if you need advice about this.

meikl ;-)
0
 
alanjbrownAuthor Commented:
Meikl

I think that I need some additional help. In  Delphi help I can't find any reference to  customsort. Is this available in Delphi 4?
An example using  multiple keys would be useful.

Alan
0
 
alanjbrownAuthor Commented:
It will not compile. Get error Variants.dcu not found

Alan
0
 
kretzschmarCommented:
hum, sorry,
just remove the variants part from the uses clause
(was introduced with delphi6)

meikl ;-)
0
All Courses

From novice to tech pro — start learning today.