Ivan
Ivan

Reputation: 85

Delphi - generic TList sort

I'm using Generics.Collections.TList and Sort method. It is working ok, but I want to sort nulls or empty values last. In ascending and descending sort order. How to implement that?

Here is my sorting function:

function TForm.SortByColumn(ColumnID: integer; SortDirRev: integer):boolean;
var
  Comparison: TComparison<TSymData>;
begin
  Result := false;

  Comparison := nil;

  if ColumnID = 0 then
    begin
      Comparison := function(const Left, Right: TSymData): integer
      begin
        Result := SortDirRev * TComparer<string>.Default.Compare(Left.Name,Right.Name);
      end;
    end
  else
    begin
      Comparison := function(const Left, Right: TSymData): integer
      begin
        Result := SortDirRev * TComparer<string>.Default.Compare(Left.Sub[ColumnID-1],Right.Sub[ColumnID-1]);
      end;
    end;

  if assigned(Comparison) then
    FSymList.Sort(TComparer<TSymData>.Construct(Comparison));

end;

Upvotes: 2

Views: 1386

Answers (1)

Andreas Rejbrand
Andreas Rejbrand

Reputation: 108929

You just need to provide a comparison function which takes empty values into account.

A comparison function is a function that takes two items A and B and returns -1 if A should go before B, +1 if A should go after B, and 0 if A and B are considered equal.

For example, to sort a list L of strings using the standard string comparer, you can do (just for reference)

L.Sort(
  TComparer<string>.Construct(
    function(const Left, Right: string): Integer
    begin
      Result := CompareStr(Left, Right)
    end
  )
);

To sort according to string length, do

L.Sort(
  TComparer<string>.Construct(
    function(const Left, Right: string): Integer
    begin
      Result := CompareValue(Left.Length, Right.Length)
    end
  )
);

Now, if you want to sort the strings normally, except that you explicitly require all empty strings to go first, you can do

L.Sort(
  TComparer<string>.Construct(
    function(const Left, Right: string): Integer
    begin
      if Left.IsEmpty and not Right.IsEmpty then
        Result := -1
      else if not Left.IsEmpty and Right.IsEmpty then
        Result := +1
      else
        Result := CompareStr(Left, Right)
    end
  )
);

To have the empty strings last, do

L.Sort(
  TComparer<string>.Construct(
    function(const Left, Right: string): Integer
    begin
      if Left.IsEmpty and not Right.IsEmpty then
        Result := +1
      else if not Left.IsEmpty and Right.IsEmpty then
        Result := -1
      else
        Result := CompareStr(Left, Right)
    end
  )
);

Upvotes: 10

Related Questions