是否有更好的方法来查找类型化数组的索引? 是否可以将每个记录存储在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.
这取决于。
如果您经常进行这些查找,则需要先对数组进行排序,然后再进行二进制搜索。如果您一直插入项目并且不经常进行查找,那么您只需要保留原样。
以下是如何对项目进行排序,首先将记录放入数组中。
//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;
如果你想搜索做:
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;
请注意,如果数组按排序顺序,则只能执行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 ....
把我们自己的变量放在TForm1的私有部分(或任何适合你目的的类)。
如果你使用TList<T>
而不是TArray<T>
那么你的生活会变得更容易。如果你将IComparer<T>
传递给你的TList<T>
构造函数,那么Sort
和IndexOf
方法可以用它来排序/查找项目。我展示了匿名和类方法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'单元。