九、泛型排序器 TComparer
pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Memo2: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
Button7: TButton;
Button8: TButton;
Button9: TButton;
Button10: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure Button7Click(Sender: TObject);
procedure Button8Click(Sender: TObject);
procedure Button9Click(Sender: TObject);
procedure Button10Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses Generics.Collections, Generics.Defaults; {必需的泛型单元}
//构建由 10 个整数组成的动态数组, 然后排序
procedure TForm1.Button1Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
begin
{构建动态数组}
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
{显示排序前}
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
{排序}
TArray.Sort<Integer>(arr); {它可以有 1个、2个、4个参数, 这里只用了一个参数, 其他是默认参数}
{显示排序结果}
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
// TArray.Sort 的第二个参数是 IComparer<T> 类型, 其默认值是: TComparer<T>.Default
procedure TForm1.Button2Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
{使用了排序器的默认值排序, 这和忽略这个参数是一样的}
TArray.Sort<Integer>(arr, TComparer<Integer>.Default);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
//同上两例, 变通了一下写法
procedure TForm1.Button3Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
Comparer: IComparer<Integer>;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
Comparer := TComparer<Integer>.Default;
TArray.Sort<Integer>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
// TArray.Sort 的后面两个参数可以指定排序范围:
procedure TForm1.Button4Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
Comparer: IComparer<Integer>;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
Comparer := TComparer<Integer>.Default;
{这里指定从第 1 个元素开始, 只给 3 个元素排序}
TArray.Sort<Integer>(arr, Comparer, 0, 3);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
//如果要倒排序, 可以建立自己的排序器, 下面就是先构建并实现了一个 TMyComparer, 然后调用:
type
TMyComparer = class(TComparer<Integer>)
public
function Compare(const Left, Right: Integer): Integer; override;
end;
{ TMyComparer }
function TMyComparer.Compare(const Left, Right: Integer): Integer;
begin
Result := Right - Left;
end;
procedure TForm1.Button5Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
Comparer: TMyComparer;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
Comparer := TMyComparer.Create;
TArray.Sort<Integer>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
Comparer.Free;
end;
// 也可以用 TComparer<T>.Construct 方法, 通过一个 TComparison 格式的函数构建排序器, 这样简单一些
function MyFunc1(const Left, Right: Integer): Integer;
begin
Result := Right - Left;
end;
procedure TForm1.Button6Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
Comparer: IComparer<Integer>;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
Comparer := TComparer<Integer>.Construct(MyFunc1);
TArray.Sort<Integer>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
//如果是给自定义类型的元素排序, 只能是自建排序器
type
TPerson = record
name: string;
age: Word;
end;
function MyFunc2(const Left, Right: TPerson): Integer;
begin
Result := Left.age - Right.age;
end;
procedure TForm1.Button7Click(Sender: TObject);
var
arr: array of TPerson;
i: Integer;
Comparer: IComparer<TPerson>;
begin
SetLength(arr, 4);
arr[0].name := 'AA'; arr[0].age := 22;
arr[1].name := 'BB'; arr[1].age := 33;
arr[2].name := 'CC'; arr[2].age := 44;
arr[3].name := 'DD'; arr[3].age := 11;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do
Memo1.Lines.Add(Format('%s : %d', [arr[i].name, arr[i].age]));
Comparer := TComparer<TPerson>.Construct(MyFunc2);
TArray.Sort<TPerson>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do
Memo2.Lines.Add(Format('%s : %d', [arr[i].name, arr[i].age]));
end;
// TStringComparer.Ordinal 是官方实现的用于 string 的排序器, 可直接使用.
//但它好像有问题(Delphi 2010 - 14.0.3513.24210), 以后的版本应该能改过来.
procedure TForm1.Button8Click(Sender: TObject);
var
arr: array of string;
i: Integer;
begin
SetLength(arr, 4);
arr[0] := '222';
arr[1] := '111';
arr[2] := 'bbb';
arr[3] := 'aaa';
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(arr[i]);
TArray.Sort<string>(arr, TStringComparer.Ordinal);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(arr[i]);
end;
//下面是实现字符串数组的到排序
function MyComparerFunc(const s1,s2: string): Integer;
begin
Result := CompareText(s2, s1);
//Result := -CompareText(s1, s2); {或者这样}
end;
procedure TForm1.Button9Click(Sender: TObject);
var
arr: array of string;
i: Integer;
Comparer: IComparer<string>;
begin
Memo1.Clear;
Memo1.Lines.CommaText := '11,33,22,AAA,CCC,BBB';
SetLength(arr, Memo1.Lines.Count);
for i := 0 to Length(arr) - 1 do arr[i] := Memo1.Lines[i];
Comparer := TComparer<string>.Construct(MyComparerFunc);
TArray.Sort<string>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(arr[i]);
end;
//可以把上一个程序简写为:
procedure TForm1.Button10Click(Sender: TObject);
var
arr: array of string;
i: Integer;
Comparer: IComparer<string>;
begin
Memo1.Clear;
Memo1.Lines.CommaText := '11,33,22,AAA,CCC,BBB';
SetLength(arr, Memo1.Lines.Count);
for i := 0 to Length(arr) - 1 do arr[i] := Memo1.Lines[i];
Comparer := TComparer<string>.Construct(
function (const s1,s2: string): Integer
begin
Result := CompareText(s2, s1);
end);
TArray.Sort<string>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(arr[i]);
end;
end.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Memo2: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
Button7: TButton;
Button8: TButton;
Button9: TButton;
Button10: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure Button7Click(Sender: TObject);
procedure Button8Click(Sender: TObject);
procedure Button9Click(Sender: TObject);
procedure Button10Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses Generics.Collections, Generics.Defaults; {必需的泛型单元}
//构建由 10 个整数组成的动态数组, 然后排序
procedure TForm1.Button1Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
begin
{构建动态数组}
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
{显示排序前}
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
{排序}
TArray.Sort<Integer>(arr); {它可以有 1个、2个、4个参数, 这里只用了一个参数, 其他是默认参数}
{显示排序结果}
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
// TArray.Sort 的第二个参数是 IComparer<T> 类型, 其默认值是: TComparer<T>.Default
procedure TForm1.Button2Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
{使用了排序器的默认值排序, 这和忽略这个参数是一样的}
TArray.Sort<Integer>(arr, TComparer<Integer>.Default);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
//同上两例, 变通了一下写法
procedure TForm1.Button3Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
Comparer: IComparer<Integer>;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
Comparer := TComparer<Integer>.Default;
TArray.Sort<Integer>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
// TArray.Sort 的后面两个参数可以指定排序范围:
procedure TForm1.Button4Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
Comparer: IComparer<Integer>;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
Comparer := TComparer<Integer>.Default;
{这里指定从第 1 个元素开始, 只给 3 个元素排序}
TArray.Sort<Integer>(arr, Comparer, 0, 3);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
//如果要倒排序, 可以建立自己的排序器, 下面就是先构建并实现了一个 TMyComparer, 然后调用:
type
TMyComparer = class(TComparer<Integer>)
public
function Compare(const Left, Right: Integer): Integer; override;
end;
{ TMyComparer }
function TMyComparer.Compare(const Left, Right: Integer): Integer;
begin
Result := Right - Left;
end;
procedure TForm1.Button5Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
Comparer: TMyComparer;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
Comparer := TMyComparer.Create;
TArray.Sort<Integer>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
Comparer.Free;
end;
// 也可以用 TComparer<T>.Construct 方法, 通过一个 TComparison 格式的函数构建排序器, 这样简单一些
function MyFunc1(const Left, Right: Integer): Integer;
begin
Result := Right - Left;
end;
procedure TForm1.Button6Click(Sender: TObject);
var
arr: array of Integer;
i: Integer;
Comparer: IComparer<Integer>;
begin
Randomize;
for i := 0 to 9 do begin
SetLength(arr, Length(arr)+1);
arr[i] := Random(10);
end;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(IntToStr(arr[i]));
Comparer := TComparer<Integer>.Construct(MyFunc1);
TArray.Sort<Integer>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(IntToStr(arr[i]));
end;
//如果是给自定义类型的元素排序, 只能是自建排序器
type
TPerson = record
name: string;
age: Word;
end;
function MyFunc2(const Left, Right: TPerson): Integer;
begin
Result := Left.age - Right.age;
end;
procedure TForm1.Button7Click(Sender: TObject);
var
arr: array of TPerson;
i: Integer;
Comparer: IComparer<TPerson>;
begin
SetLength(arr, 4);
arr[0].name := 'AA'; arr[0].age := 22;
arr[1].name := 'BB'; arr[1].age := 33;
arr[2].name := 'CC'; arr[2].age := 44;
arr[3].name := 'DD'; arr[3].age := 11;
Memo1.Clear;
for i := 0 to Length(arr) - 1 do
Memo1.Lines.Add(Format('%s : %d', [arr[i].name, arr[i].age]));
Comparer := TComparer<TPerson>.Construct(MyFunc2);
TArray.Sort<TPerson>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do
Memo2.Lines.Add(Format('%s : %d', [arr[i].name, arr[i].age]));
end;
// TStringComparer.Ordinal 是官方实现的用于 string 的排序器, 可直接使用.
//但它好像有问题(Delphi 2010 - 14.0.3513.24210), 以后的版本应该能改过来.
procedure TForm1.Button8Click(Sender: TObject);
var
arr: array of string;
i: Integer;
begin
SetLength(arr, 4);
arr[0] := '222';
arr[1] := '111';
arr[2] := 'bbb';
arr[3] := 'aaa';
Memo1.Clear;
for i := 0 to Length(arr) - 1 do Memo1.Lines.Add(arr[i]);
TArray.Sort<string>(arr, TStringComparer.Ordinal);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(arr[i]);
end;
//下面是实现字符串数组的到排序
function MyComparerFunc(const s1,s2: string): Integer;
begin
Result := CompareText(s2, s1);
//Result := -CompareText(s1, s2); {或者这样}
end;
procedure TForm1.Button9Click(Sender: TObject);
var
arr: array of string;
i: Integer;
Comparer: IComparer<string>;
begin
Memo1.Clear;
Memo1.Lines.CommaText := '11,33,22,AAA,CCC,BBB';
SetLength(arr, Memo1.Lines.Count);
for i := 0 to Length(arr) - 1 do arr[i] := Memo1.Lines[i];
Comparer := TComparer<string>.Construct(MyComparerFunc);
TArray.Sort<string>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(arr[i]);
end;
//可以把上一个程序简写为:
procedure TForm1.Button10Click(Sender: TObject);
var
arr: array of string;
i: Integer;
Comparer: IComparer<string>;
begin
Memo1.Clear;
Memo1.Lines.CommaText := '11,33,22,AAA,CCC,BBB';
SetLength(arr, Memo1.Lines.Count);
for i := 0 to Length(arr) - 1 do arr[i] := Memo1.Lines[i];
Comparer := TComparer<string>.Construct(
function (const s1,s2: string): Integer
begin
Result := CompareText(s2, s1);
end);
TArray.Sort<string>(arr, Comparer);
Memo2.Clear;
for i := 0 to Length(arr) - 1 do Memo2.Lines.Add(arr[i]);
end;
end.
dfm
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 321
ClientWidth = 318
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Memo1: TMemo
Left = 0
Top = 0
Width = 89
Height = 321
Align = alLeft
Lines.Strings = (
'Memo1')
TabOrder = 0
ExplicitHeight = 299
end
object Button1: TButton
Left = 120
Top = 8
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 1
OnClick = Button1Click
end
object Button2: TButton
Left = 120
Top = 39
Width = 75
Height = 25
Caption = 'Button2'
TabOrder = 2
OnClick = Button2Click
end
object Button3: TButton
Left = 120
Top = 70
Width = 75
Height = 25
Caption = 'Button3'
TabOrder = 3
OnClick = Button3Click
end
object Memo2: TMemo
Left = 219
Top = 0
Width = 99
Height = 321
Align = alRight
Lines.Strings = (
'Memo2')
TabOrder = 4
ExplicitHeight = 299
end
object Button4: TButton
Left = 120
Top = 101
Width = 75
Height = 25
Caption = 'Button4'
TabOrder = 5
OnClick = Button4Click
end
object Button5: TButton
Left = 120
Top = 132
Width = 75
Height = 25
Caption = 'Button5'
TabOrder = 6
OnClick = Button5Click
end
object Button6: TButton
Left = 120
Top = 163
Width = 75
Height = 25
Caption = 'Button6'
TabOrder = 7
OnClick = Button6Click
end
object Button7: TButton
Left = 120
Top = 194
Width = 75
Height = 25
Caption = 'Button7'
TabOrder = 8
OnClick = Button7Click
end
object Button8: TButton
Left = 120
Top = 225
Width = 75
Height = 25
Caption = 'Button8'
TabOrder = 9
OnClick = Button8Click
end
object Button9: TButton
Left = 120
Top = 256
Width = 75
Height = 25
Caption = 'Button9'
TabOrder = 10
OnClick = Button9Click
end
object Button10: TButton
Left = 120
Top = 287
Width = 75
Height = 25
Caption = 'Button10'
TabOrder = 11
OnClick = Button10Click
end
end
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 321
ClientWidth = 318
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Memo1: TMemo
Left = 0
Top = 0
Width = 89
Height = 321
Align = alLeft
Lines.Strings = (
'Memo1')
TabOrder = 0
ExplicitHeight = 299
end
object Button1: TButton
Left = 120
Top = 8
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 1
OnClick = Button1Click
end
object Button2: TButton
Left = 120
Top = 39
Width = 75
Height = 25
Caption = 'Button2'
TabOrder = 2
OnClick = Button2Click
end
object Button3: TButton
Left = 120
Top = 70
Width = 75
Height = 25
Caption = 'Button3'
TabOrder = 3
OnClick = Button3Click
end
object Memo2: TMemo
Left = 219
Top = 0
Width = 99
Height = 321
Align = alRight
Lines.Strings = (
'Memo2')
TabOrder = 4
ExplicitHeight = 299
end
object Button4: TButton
Left = 120
Top = 101
Width = 75
Height = 25
Caption = 'Button4'
TabOrder = 5
OnClick = Button4Click
end
object Button5: TButton
Left = 120
Top = 132
Width = 75
Height = 25
Caption = 'Button5'
TabOrder = 6
OnClick = Button5Click
end
object Button6: TButton
Left = 120
Top = 163
Width = 75
Height = 25
Caption = 'Button6'
TabOrder = 7
OnClick = Button6Click
end
object Button7: TButton
Left = 120
Top = 194
Width = 75
Height = 25
Caption = 'Button7'
TabOrder = 8
OnClick = Button7Click
end
object Button8: TButton
Left = 120
Top = 225
Width = 75
Height = 25
Caption = 'Button8'
TabOrder = 9
OnClick = Button8Click
end
object Button9: TButton
Left = 120
Top = 256
Width = 75
Height = 25
Caption = 'Button9'
TabOrder = 10
OnClick = Button9Click
end
object Button10: TButton
Left = 120
Top = 287
Width = 75
Height = 25
Caption = 'Button10'
TabOrder = 11
OnClick = Button10Click
end
end