1

总结:

TList.IndexOf(在单元Classes.pas中定义的TList)线性迭代包含的项目,并比较引用。TList.IndexOf(在Generics.Collections.pas单元中定义的TList)也线性迭代包含的项目,但使用比较器来比较项目是否相等。

TList.Sort 和 TList.Sort 都可以使用比较器。

=================================================

对于以下单元中定义的 TForceList 类型的实例,我可以使用

instance.Sort(@ForceCompare);

使用其值字段作为排序标准对其进行快速排序。但是,当我打电话时

instance.IndexOf(AnotherInstance)

我想使用它的 ElementZ 字段作为比较标准,即ForceEqual函数。我想知道我怎样才能做到这一点?

PS:如果使用泛型集合,我想我可以使用

TList<TForce>.Create(TComparer<TForce>.Construct(ForceEqual));

那个单位:

    unit uChemParserCommonForce;

    interface

    uses
      uMathVector3D,
      Contnrs;

    type

      TForce = class;
      TForceList = class;

      TForce = class
      private
        FElementZ: Integer;
        FValue: TVector3D;
      public
        property ElementZ: Integer read FElementZ;
        property Value: TVector3D read FValue;
        constructor Create(aElementZ: Integer; aX, aY, aZ: Double);
        function ToString(): string; {$IF DEFINED(FPC) OR DEFINED(VER210)} override; {$IFEND}
      end;

      // Mastering Delphi 6 - Chapter 5 -
      TForceList = class(TObjectList)
      protected
        procedure SetObject(Index: Integer; Item: TForce);
        function GetObject(Index: Integer): TForce;
      public
        function Add(Obj: TForce): Integer;
        procedure Insert(Index: Integer; Obj: TForce);
        property Objects[Index: Integer]: TForce read GetObject
          write SetObject; default;
      end;

    function ForceCompare(Item1, Item2: Pointer): Integer;
    function ForceEqual(Item1, Item2: Pointer): Boolean;

    implementation

    uses
      Math, SysUtils;

    function ForceCompare(Item1, Item2: Pointer): Integer;
    begin
      // Ascendent
      //  Result := CompareValue(TForce(Item1).Value.Len, TForce(Item2).Value.Len);
      // Descendent
      Result := CompareValue(TForce(Item2).Value.Len, TForce(Item1).Value.Len);
    end;

    function ForceEqual(Item1, Item2: Pointer): Boolean;
    begin
      Result := TForce(Item1).ElementZ = TForce(Item2).ElementZ;
    end;

    constructor TForce.Create(aElementZ: Integer; aX, aY, aZ: Double);
    begin
      FElementZ := aElementZ;
      FValue := TVector3D.Create(aX, aY, aZ);
    end;

    function TForce.ToString: string;
    begin
      Result := IntToStr(FElementZ) + ' X: ' + FloatToStr(FValue.X) + ' Y: ' +
        FloatToStr(FValue.Y) + ' Z: ' + FloatToStr(FValue.Z);
    end;

    { TForceList }

    function TForceList.Add(Obj: TForce): Integer;
    begin
      Result := inherited Add(Obj);
    end;

    procedure TForceList.SetObject(Index: Integer; Item: TForce);
    begin
      inherited SetItem(Index, Item);
    end;

    function TForceList.GetObject(Index: Integer): TForce;
    begin
      Result := inherited GetItem(Index) as TForce;
    end;

    procedure TForceList.Insert(Index: Integer; Obj: TForce);
    begin
      inherited Insert(Index, Obj);
    end;

    end.
4

3 回答 3

2

非泛型TObjectListuses TList.IndexOf,它简单地遍历内部数组并比较指针。

同样,泛型TObjectList<T>uses TList<T>.IndexOf,它使用IComparer. TList<T>.Sort使用TArray.Sort<T>传入IComparer列表创建时分配的任何内容。

比较器是私有的,并且仅在列表构造函数中分配,因此我看不到覆盖此行为的简单方法。

更新

TList<T>提供并重载Sort接受比较器作为参数,而不修改私有比较器。因此,您可以使用一个比较器进行排序,而 indexof 可以使用不同的比较器。

于 2011-03-10T21:37:17.503 回答
2

Sort 方法背后的整个想法是它真正对列表进行排序......换句话说,在调用 sort 方法之后,列表中元素的物理顺序被改变以满足排序标准。

IndexOf 方法,正如您在自己的 Delphi RTL 代码中所见,只是通过引用返回第一个匹配元素的物理索引的线性搜索。

返回的索引可用于检索列表中的对象,如下所示:

SomeIndex := AList.IndexOf(SomeObject);
//more code...
//you can re-use the reference...
//and maybe more...
SomeObject := AList[SomeIndex];

您会明白为什么,IndexOf 方法不应返回基于与列表的物理顺序不同的标准的索引......如果您首先调用 Sort,则会发生这种情况,物理顺序反映了传递的排序标准。

也就是说,看起来你可能想要

  • 维护两个不同的列表,按不同的标准排序,并在适当的时候使用一个或另一个。
  • 根据应用程序在给定时间处理的操作的适用标准重新排序列表。

更高的性能取决于您的应用程序如何使用这些对象、它正在处理的数据量,甚至是您的进程在运行时可用的内存。

于 2011-03-10T21:57:22.937 回答
1

不是标准的 TObjectList。它(实际上是基本 TList)是为支持使用 CustomSort 的自定义排序功能而编写的,但是对于自定义 IndexOf 没有这样的规定。当然,您可以编写自己的实现以这种方式工作。

于 2011-03-10T21:25:47.950 回答