Reputation: 14873
What is the easiest way to get the maximum value in a TList<Integer>
?
function GetMaximum(AList: TList<Integer>): Integer;
begin
Assert(AList.Count > 0);
Result := ?;
end;
I read that C# has a AList.Max
, is there something like that in Delphi?
Upvotes: 5
Views: 3482
Reputation: 21748
I agree that using the Spring collections is probably the easiest way. However there may be reasons to not use them (already using Generics.Collections all over the place).
So here is how to make a new type that extends TEnumerable<T>
with a function Max: T
.
type
Enumerable<T> = record
private
source: TEnumerable<T>;
public
function Max: T;
class operator Implicit(const value: TEnumerable<T>): Enumerable<T>;
end;
class operator Enumerable<T>.Implicit(
const value: TEnumerable<T>): Enumerable<T>;
begin
Result.source := value;
end;
function Enumerable<T>.Max: T;
var
default: IComparer<T>;
x, y: T;
flag: Boolean;
begin
if not Assigned(source) then
raise EArgumentNilException.Create('Source');
default := TComparer<T>.Default;
flag := False;
for x in source do
begin
if flag then
begin
if default.Compare(x, y) > 0 then
y := x;
end
else
begin
y := x;
flag := True;
end;
end;
if flag then
Result := y
else
raise EListError.Create('source is empty');
end;
The code is basically a port of the .Net Enumerable.Max<T>
extension method from System.Linq
. You can use it just like in Nicks example.
The interesting thing for those interested in their binary size: linker is able to remove the methods that are never used.
Upvotes: 1
Reputation: 17138
Here's an alternative answer: Use the Spring.Collections.pas
unit from the Spring4D framework: (found here: http://code.google.com/p/delphi-spring-framework/)
program ListEnumerableDemo;
{$APPTYPE CONSOLE}
uses
System.SysUtils
, Spring.Collections;
var
List: IList<Integer>;
Enumerable: IEnumerable<Integer>;
begin
try
List := TCollections.CreateList<Integer>;
List.AddRange([1,6,2,9,54,3,2,7,9,1]);
Enumerable := List;
WriteLn(Enumerable.Max);
ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Upvotes: 9
Reputation: 613272
Here's a fun example with a MaxValue
implementation on a generic container:
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.Generics.Defaults, System.Generics.Collections;
type
TMyList<T> = class(TList<T>)
public
function MaxValue: T;
end;
{ TMyList<T> }
function TMyList<T>.MaxValue: T;
var
i: Integer;
Comparer: IComparer<T>;
begin
if Count=0 then
raise Exception.Create('Cannot call TMyList<T>.MaxValue on an empty list');
Comparer := TComparer<T>.Default;
Result := Self[0];
for i := 1 to Count-1 do
if Comparer.Compare(Self[i], Result)>0 then
Result := Self[i];
end;
var
IntList: TMyList<Integer>;
DoubleList: TMyList<Double>;
StringList: TMyList<string>;
begin
IntList := TMyList<Integer>.Create;
IntList.AddRange([10, 5, 12, -49]);
Writeln(IntList.MaxValue);
DoubleList := TMyList<Double>.Create;
DoubleList.AddRange([10.0, 5.0, 12.0, -49.0]);
Writeln(DoubleList.MaxValue);
StringList := TMyList<string>.Create;
StringList.AddRange(['David Heffernan', 'Uwe Raabe', 'Warren P', 'Jens Mühlenhoff']);
Writeln(StringList.MaxValue);
Readln;
end.
Because we cannot come up with a generic equivalent to low(Integer)
I raise an exception when the method is called on an empty list.
The output is:
12 1.20000000000000E+0001 Warren P
Upvotes: 10
Reputation: 14873
Using for .. in
:
function GetMaximum(AList: TList<Integer>): Integer;
var
I: Integer
begin
Assert(AList.Count > 0);
Result := Low(Integer);
for I in AList do
if I > Result then
Result := I;
end;
Upvotes: 3