Delphi 如何在通用TList中获得最大值<;整数>;?

Delphi 如何在通用TList中获得最大值<;整数>;?,delphi,delphi-xe2,Delphi,Delphi Xe2,在t列表中获取最大值的最简单方法是什么 函数GetMaximum(AList:TList):整数; 开始 断言(AList.Count>0); 结果:=?; 结束; 我读到C#有一个AList.Max,Delphi中有类似的东西吗?使用for。。在中: function GetMaximum(AList: TList<Integer>): Integer; var I: Integer begin Assert(AList.Count > 0); Result :

t列表中获取最大值的最简单方法是什么

函数GetMaximum(AList:TList):整数; 开始 断言(AList.Count>0); 结果:=?; 结束;

我读到C#有一个
AList.Max
,Delphi中有类似的东西吗?

使用
for。。在
中:

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;
函数GetMaximum(AList:TList):整数; 变量 I:整数 开始 断言(AList.Count>0); 结果:=低(整数); 因为我知道 如果我>结果,那么 结果:=I; 结束;
下面是一个有趣的示例,它在通用容器上实现了
MaxValue

{$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.

这里有一个替代答案:使用Spring4D框架中的
Spring.Collections.pas
单元:(可在此处找到:)

程序ListNumerableDemo;
{$APPTYPE控制台}
使用
System.SysUtils
春季系列;
变量
名单:IList;
可枚举:IEnumerable;
开始
尝试
列表:=TCollections.CreateList;
列表.AddRange([1,6,2,9,54,3,2,7,9,1]);
可枚举:=列表;
WriteLn(可枚举的最大值);
ReadLn;
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
结束。

我同意使用Spring集合可能是最简单的方法。但是,可能有理由不使用它们(到处都在使用泛型集合)

下面是如何使用
函数Max:T
创建一个扩展
TEnumerable
的新类型

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;
类型
可枚举=记录
私有的
资料来源:微不足道;
公众的
函数Max:T;
类运算符隐式(常量值:TEnumerable):可枚举;
结束;
类运算符可枚举。隐式(
常量值:TEnumerable):可枚举;
开始
Result.source:=值;
结束;
函数可枚举。最大值:T;
变量
默认值:IComparer;
x、 y:T;
标志:布尔;
开始
如果未分配(源),则
引发eargumentnileexception.Create('Source');
默认值:=TComparer.default;
标志:=假;
对于源代码中的x
开始
如果旗子那么
开始
如果为默认值,则比较(x,y)>0,然后
y:=x;
结束
其他的
开始
y:=x;
标志:=真;
结束;
结束;
如果旗子那么
结果:=y
其他的
创建('源为空');
结束;
该代码基本上是
System.Linq
中.Net
Enumerable.Max
扩展方法的一个端口。您可以像在Nicks示例中一样使用它


对于那些对二进制大小感兴趣的人来说,有趣的事情是:链接器能够删除从未使用过的方法。

NET方式:当然,.NET有可爱的扩展方法来做这类事情。……定义IEnumerable接口,提供类似LINQ的可枚举扩展方法。推荐@Marjan Venema:在泛型集合中,定义了TEnumerable类。另一方面,在Spring Delphi框架中,集合是基于接口的。在单元Spring.Collections.list中定义了一个类TList,它提供扩展方法,并最终实现IEnumerable(T)。例如,您可以调用List.Max,也可以调用List.Reversed。另请参见。@Marjan Venema:Nick Hodges还写了一系列关于依赖注入的优秀文章。你也有和。就像我说的:推荐!这可以用一种与.net中的
IEnumerable
功能相当的方式来实现吗?换句话说,你能使用泛型/特征为GetMaximum做一个泛型实现吗?@Warren--Spring.Collections.pas单元有IEnumerable,这将使它变得简单。+1,用于使用
ENumerable
,因为它根本不是
TList
问题。由于IList继承自IEnumerable,我们可以使用List.Max,而不必将其强制转换为IEnumerable:)@Jeroen我完全不理解这个评论。答案使用通用列表。只是不是Generics.Collections.Spring中的变体。在春季,不仅仅是
IList
公开了
IEnumerable
。这是尼克回答的关键。@David:问得好。我尝试了上面的演示,并注释掉了填充列表的AddRange。它做了我希望它能做的事。引发异常EInvalidOpException,并显示消息“此序列为空” 12 1.20000000000000E+0001 Warren P
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. 
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;