Delphi如何搜索类型记录数组的索引

时间:2018-09-06 12:34:27

标签: delphi

找到Typed数组的索引是否有更好的方法?
是否可以将每条记录存储在Tlist或其他内容中,然后找到索引。

例如,我喜欢拥有index=FindIndexof(12345)和返回游戏数组索引的函数。
目前,我正在使用以下代码,但我认为是错误的,因为我将event_id存储在内存中的两个位置。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyEvent = record
    Event_id: longint;
    Myarray: array[0..2] of Integer;
    MyString: string;
  end;

const max_events=100;

var
  Form1: TForm1;
  MyEvents:Array[0..max_events] of TMyEvent;
  MyListIndex:  TStringlist;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var x:Integer;
begin
  randomize;
  MyListIndex:=TStringlist.create;
  for x:=0 to max_events do
  begin
    with myEvents[x] do
    begin
      Event_id:=Random(10000)+1;
      Myarray[0]:=1;
      Myarray[1]:=2;
      MyListIndex.add('^'+formatfloat('0',Event_id)+'^');
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var MyIndexId:Longint;
begin
  MyIndexId:=MyListIndex.indexof('^12345^');
  // and after I can process
  // myEvents[MyIndexId].Event_id
end;

end.

2 个答案:

答案 0 :(得分:2)

要视情况而定。

如果经常执行这些查找,则需要先对数组进行排序,然后再进行二进制搜索。如果您一直插入项目而又不经常查找,那么您只希望保持原样。

这里是对项目进行排序的方法,首先将记录放入数组中。

//Pull in TArray.Sort and TArray.BinarySearch
uses System.Generics.Collections;


Events: TArray<TMyEvent>;
....
SetLength(Events, MyEventCount); 
for i:= 0 to MyEventCount-1 do begin
  //Read in events
end;

现在使用

对它们进行排序
procedure SortEvents(var Events: TArray<TMyEvent>);
begin
  TArray.Sort<TMyEvent>(Events, TDelegatedComparer<TMyEvent>.Construct(
    function(const Left, Right: TMyEvent): Integer
    begin
      if Left.EventId > Right.EventId then Exit(1);
      if Left.EventId < Right.EventId then Exit(-1);
      Result:= 0;  //or raise an error if duplicates are not allowed.
    end
  ));
end;

请参阅:TArray.Sort<T>

如果要搜索,请执行以下操作:

function EventByIndex(const Events: TArray<TMyEvent>; EventId: longint; out Index: integer): TMyEvent;
var
  Dummy: TMyEvent;
  Found: boolean;
begin
  Dummy.EventId:= EventId;
  Found:= TArray.BinarySearch(Events,  Dummy, Index, 
    TDelegatedComparer<TMyEvent>.Construct(
    function(const Left, Right: TMyEvent): Integer
    begin
      if Left.EventId > Right.EventId then Exit(1);
      if Left.EventId < Right.EventId then Exit(-1);
      Result:= 0;  //or raise an error if duplicates are not allowed.
    end
  ));
  if Found then Result:= Events[Index]
  else Index:= -1;
end; 

请参阅:TArray.BinarySearch<T>

请注意,如果数组按排序顺序,则只能执行BinarySearch。
如果EventID不是唯一的,则此函数将仅返回单个结果,但是具有相同EventId的项目将紧邻返回的项目,因此您应该可以从那里开始工作。

如果您只想进行线性搜索,请执行以下操作:

function EventIndexOf(const Events: TArray<MyEvent>; EventId: longint): integer;
var
  i: integer;
begin
  for i:= 0 to High(Events) do if Events[i].EventId = EventId then Exit(i);
end;

备注
显然,无需存储重复数据。将数字存储在Int中(如果数量很大则存储在Int64中),将文本存储在字符串中。
请不要滥用TStringList来存储记录数据。 TList<TSomeRecord>TArray<TSomeRecord>更适合于此目的。

全局变量不正确,请尽量不要编写这样的代码:

unit X;
interface
...
var
  Form1: TForm1;
  MyEvents:Array[0..max_events] of TMyEvent;
  MyListIndex:  TStringlist;
implementation ....

将我们自己的vars放在TForm1的私有部分(或任何适合您目的的类)中。

答案 1 :(得分:0)

如果您使用TList<T>而不是TArray<T>,那么生活将会变得更加轻松。如果将IComparer<T>传递给TList<T>构造函数,则SortIndexOf方法可以使用它来排序/查找项目。我展示了匿名和类方法IComparer<TMyRec>用法的示例。您可以注释掉不喜欢的人。

intrface

type
  TMyRec = packed record
    a, b : integer;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    function compareRecs( const left_, right_ : TMyRec ) : integer;
  public
    { Public declarations }
  end;

implementation

uses
  Generics.Collections, Generics.Defaults;

function TForm1.compareRecs( const left_, right_ : TMyRec ) : integer;
begin
  result := left_.a - right_.a;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  iC : IComparer<TMyRec>;
  aL : TList<TMyRec>;
  aMR : TMyRec;
  i : integer;
begin
  iC := TComparer<TMyRec>.Construct( function ( const left_, right_ : TMyRec ) : integer begin result := left_.a - right_.a; end );
  //iC := TComparer<TMyRec>.Construct( compareRecs );
  aL := TList<TMyRec>.create( iC );
  try
    for i := 1 to 5 do
    begin
      aMR.a := 6-i;
      aMR.b := i;
      aL.Add( aMR );
    end;
    // The order of the items is in reverse order (by TMyRec.a)
    aL.Sort;
    // The order of the items is in the right order (by TMyRec.a)
    aMR.a := 3;
    i := aL.indexOf( aMR );
    // i = 2
  finally
    aL.Free;
  end;
end;

当您通过记录调用indexOf方法时,结果索引仅取决于比较器函数中使用的记录值。在这种情况下,TMyRec.a。 要使用通用列表(TList<T>),必须使用Generics.Collections单元。如果要使用自定义排序,请使用IComparer<T>实现。为此,您必须使用“ Generics.Defaults”单元。