Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I sort a generic list using a custom comparer?

Tags:

sorting

delphi

I'm kinda a Delphi-newbie and I don't get how the Sort method of a TList of Records is called in order to sort the records by ascending integer value. I have a record like the following:

 type    TMyRecord = record      str1: string;      str2: string;      intVal: integer;    end; 

And a generic list of such records:

TListMyRecord = TList<TMyRecord>; 

Have tried to find a code-example in the help files and found this one:

MyList.Sort(@CompareNames); 

Which I can't use, since it uses classes. So I tried to write my own compare function with a little different parameters:

function CompareIntVal(i1, i2: TMyRecord): Integer; begin   Result := i1.intVal - i2.intVal; end; 

But the compiler always throws a 'not enough parameters' - error when I call it with open.Sort(CompareIntVal);, which seems obvious; so I tried to stay closer to the help file:

function SortKB(Item1, Item2: Pointer): Integer; begin   Result:=PMyRecord(Item1)^.intVal - PMyRecord(Item2)^.intVal; end; 

with PMyRecord as PMyRecord = ^TMyRecord;

I have tried different ways of calling a function, always getting some error...

like image 531
p1.e Avatar asked Nov 06 '12 13:11

p1.e


People also ask

Can you sort a list in C#?

Sort() Method Set -1. List<T>. Sort() Method is used to sort the elements or a portion of the elements in the List<T> using either the specified or default IComparer<T> implementation or a provided Comparison<T> delegate to compare list elements.

How do you sort collections in C#?

Sort(IComparer) This method is used to sort the elements in the entire ArrayList using the specified comparer. This method is an O(n log n) operation, where n is Count; in the worst case, it is an O(n^2) operation. Syntax: public virtual void Sort (IComparer comparer);

Which field type in a list is not sortable?

You cannot sort a list by an array-based field, such as a Glide list.


1 Answers

The Sort overload you should be using is this one:

procedure Sort(const AComparer: IComparer<TMyRecord>); 

Now, you can create an IComparer<TMyRecord> by calling TComparer<TMyRecord>.Construct. Like this:

var   Comparison: TComparison<TMyRecord>; .... Comparison :=    function(const Left, Right: TMyRecord): Integer   begin     Result := Left.intVal-Right.intVal;   end; List.Sort(TComparer<TMyRecord>.Construct(Comparison)); 

I've written the Comparison function as an anonymous method, but you could also use a plain old style non-OOP function, or a method of an object.

One potential problem with your comparison function is that you may suffer from integer overflow. So you could instead use the default integer comparer.

Comparison :=    function(const Left, Right: TMyRecord): Integer   begin     Result := TComparer<Integer>.Default.Compare(Left.intVal, Right.intVal);   end; 

It might be expensive to call TComparer<Integer>.Default repeatedly so you could store it away in a global variable:

var   IntegerComparer: IComparer<Integer>; .... initialization   IntegerComparer := TComparer<Integer>.Default; 

Another option to consider is to pass in the comparer when you create the list. If you only ever sort the list using this ordering then that's more convenient.

List := TList<TMyRecord>.Create(TComparer<TMyRecord>.Construct(Comparison)); 

And then you can sort the list with

List.Sort; 
like image 117
David Heffernan Avatar answered Sep 22 '22 04:09

David Heffernan