找到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.
答案 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;
请注意,如果数组按排序顺序,则只能执行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>
构造函数,则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”单元。