📜 ⬆️ ⬇️

We use generics in RAD Studio Delphi. Create a library of sorting lists of similar objects

Today we will create in RAD Studio Delphi a library of classes that implement sorting lists of similar objects.

Purpose of the task


An application developer should get a tool to create child classes in which you can:


The output should be a class library that allows you to:
')

When creating it is necessary to consider that the solution must satisfy the following model:


Getting started


Sorting by ascending is a permutation of the elements of a data set so that as a result each subsequent element of the set is greater than the previous one. Sorting in descending order is the same, only the traversal of the resulting dataset must be started from the end.

Comparison of objects

To understand which element of the data set is greater than another, you need to use a comparison operator for basic types. And what about objects? The base module System.Generics.Defaults includes the interface we need and the implementation of the class

IComparer<T> = interface function Compare(const Left, Right: T): Integer; end; TComparer<T> = class(TInterfacedObject, IComparer<T>) public class function Default: IComparer<T>; class function Construct(const Comparison: TComparison<T>): IComparer<T>; function Compare(const Left, Right: T): Integer; virtual; abstract; end; 

In the interface, we see the only Compare method of the form.

 TComparison<T> = reference to function(const Left, Right: T): Integer; 

At the input there are two parameters of the object type, and the output is an integer (0 - objects are equal, -1 - the first is less than the second, 1 - the first is more than the second).

To compare our objects, we will use our own comparison functions, which describe the logic of comparison rules for each type of objects. We enclose such functions in a separate class TAllComparison . It describes all our comparison functions, they have the same look.

  TComparison<T> = reference to function(const Left, Right: T): Integer; 

And the TComparer (T) class just serves to compare two objects by calling the Compare method.
You can use the default comparison, or create your own comparison method Construct , which we will do.

For convenience, the description of all objects will be stored in a separate AllObjects module. Here we will store the description of all 100 objects created by us.

Operations with objects

For implementing operations with list objects in Delphi, we already have the parameterized class we need, also known as a generic, with the methods we need

  TList<T> = class(TEnumerable<T>) 

In general, universal parameterized types (generics) appeared in Delphi 2009, but for our example I use RAD Studio Berlin 10.1 UPD1. If you do not compile something, you will need to finish the example for your version of Delphi.

We write the main class of our library the successor of TList (T)

 //         type TAppliedObjectList<T> = class(TList<T>) private type TSorting<T> = reference to function(var Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer): Integer; var FCS: TCriticalSection; //        FComparer: IComparer<T>; //       Target: Array of T; //   ,      // ,        <i>Private</i> public constructor Create; overload; constructor Create(const AComparer: IComparer<T>); overload; destructor Destroy; override; //           //        //   , ,     <i>MaxInt</i> function SortBy<T>(const AProc: TSorting<T>): Integer; overload; end; 

The main method of our task is SortBy , we describe its use further.

Sort objects

We write the class TAllSort , which contains the description of all 100 sorting methods of the form:

 TSorting<T> = reference to function(var Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer): Integer; 

At the input, the method gets an array of data from the list, a method for comparing objects, the starting position for sorting, the number of elements in the set. At the output we get the number of permutations made in the data set.

 type //      TSorting<T> TSorting<T> = reference to function(var Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer): Integer; //  ,   100   TAllSort = class public // ***    class function BubbleSort<T>(var Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer): Integer; // ***   class function QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>; Index, Count: Integer): Integer; end; 

For convenience, all sorting methods will be kept in a separate module SortMethods .

Demonstration


As a demonstration of the solution, I present 2 sorting mechanisms: “Fast” and “Bubble”. We will sort 2 types of objects: a list of two-dimensional vectors (ordered pairs) of type Integer and a list with strings.

First, sort the array of strings by “bubbles”:

 procedure TfmMainTest.Button4Click(Sender: TObject); var //    TAppliedObjectList<String> // ,        MyClass: TAppliedObjectList<String>; i: Integer; begin Memo1.Clear; try //    , //           //  IComparer<T> MyClass := TAppliedObjectList<String>.Create(TComparer<String>.Default); try Memo1.Lines.Text := '         ' + sLineBreak + '  ,     .' + sLineBreak + '       ' + sLineBreak + '        .' + sLineBreak + '         ,' + sLineBreak + '        .' + sLineBreak + '          ,' + sLineBreak + '     ,   .' + sLineBreak + '   ,    ' + sLineBreak + '    .' + sLineBreak + '  ,   ' + sLineBreak + '     .'; //     Memo for i := 0 to Memo1.Lines.Count - 1 do begin MyClass.Add(Memo1.Lines[i]); end; //    "" i := MyClass.SortBy<String>(TAllSort.BubbleSort<String>); //    Memo1.Lines.Add(sLineBreak + 'Turns: ' + i.ToString); //    Memo1.Lines.Add(' :'); for i := 0 to MyClass.Count - 1 do begin Memo1.Lines.Add(MyClass.Items[i]); end; finally //    ,      MyClass.Free; end; except on E: Exception do Memo1.Lines.Add(E.Message); end; end; 

Got the result:



And now "quickly" sort the array of two-dimensional vectors:

 procedure TfmMainTest.Button3Click(Sender: TObject); var //    TAppliedObjectList<TVector2D> // ,       TVector2D MyClass: TAppliedObjectList<TVector2D>; //    TVector2D v: TVector2D; i: Integer; begin Memo1.Clear; try //     , //       //  TAllComparison.Compare_TVector2D MyClass := TAppliedObjectList<TVector2D>.Create (TComparer<TVector2D>.Construct(TAllComparison.Compare_TVector2D)); try //     2D  Memo1.Lines.Add(' :'); v.Create(10, 21); MyClass.Add(v); Memo1.Lines.Add(v.ToString); v.Create(-10, 20); MyClass.Add(v); Memo1.Lines.Add(v.ToString); v.Create(-10, -2); MyClass.Add(v); Memo1.Lines.Add(v.ToString); v.Create(-1, 7); MyClass.Add(v); Memo1.Lines.Add(v.ToString); //   ""  i := MyClass.SortBy<TVector2D>(TAllSort.QuickSort<TVector2D>); //    Memo1.Lines.Add(sLineBreak + 'Turns: ' + i.ToString); //    Memo1.Lines.Add(' :'); for i := 0 to MyClass.Count - 1 do begin Memo1.Lines.Add(MyClass.Items[i].ToString); end; finally //    ,      if Assigned(MyClass) then MyClass.Free; end; except on E: Exception do Memo1.Lines.Add(E.Message); end; end; 

Here is the result with vectors:



Source codes


» Sample Delphi source codes for working with the TAppliedObjectList class

Thanks for attention!

Source: https://habr.com/ru/post/314780/


All Articles