如何使局部数组变量有条件地指向开放数组参数?
How to make a local array variable conditionally points to an open array parameter?
我正在尝试有条件地分配一个本地开放数组变量,以便它指向一个常量开放数组参数:
uses
System.Generics.Collections,
System.Generics.Defaults;
type
TArray = class(System.Generics.Collections.TArray)
public
class function SameValues<T>(const AValuesA: array of T; AValuesB: array of T; const AComparer: IEqualityComparer<T>; AOrderMatters : Boolean = True) : Boolean; overload; static;
end;
...
class function TArray.SameValues<T>(const AValuesA: array of T; AValuesB: array of T; const AComparer: IEqualityComparer<T>; AOrderMatters : Boolean = True) : Boolean;
var
ArrA : TArray<T>;
ArrB : TArray<T>;
i : integer;
begin
//checking sizes
if(Length(AValuesA) <> Length(AValuesB)) then
begin
Result := False;
Exit;
end;
if(AOrderMatters) then
begin
//I don't need to change the arrays, so I could directly point to the open array parameters
ArrA := AValuesA;
ArrB := AValuesB;
end else
begin
//copying to local arrays
SetLength(ArrA, Length(AValuesA));
TArray.Copy<T>(AValuesA, ArrA, Length(AValuesA));
SetLength(ArrB, Length(AValuesB));
TArray.Copy<T>(AValuesB, ArrB, Length(AValuesB));
//sorting local arrays
TArray.Sort<T>(ArrA);
TArray.Sort<T>(ArrB);
end;
//comparing elements
i := 0;
while(i < Length(ArrA)) do
begin
if(not AComparer.Equals(ArrA[i], ArrB[i])) then
begin
Result := False;
Exit;
end;
Inc(i);
end;
Result := True;
end;
编译时,在以下位置引发 E2010 错误:
//I don't need to change the arrays, so I could directly point to the open array parameters
ArrA := AValuesA;
ArrB := AValuesB;
E2010 Incompatible types: 'Dynamic array' and 'array of T'
我试过以下方法:
ArrA := @AValuesA;
ArrB := @AValuesB;
它编译但随后在运行时引发 AV 异常(最重要的是,我不知道这是否是一种安全的方法)。
这是我的测试应用程序代码:
uses
System.Generics.Defaults;
procedure TForm1.FormCreate(Sender: TObject);
var
ArrA : array of string;
ArrB : array of string;
begin
SetLength(ArrA, 2);
ArrA[0] := 'hello';
ArrA[1] := 'world';
SetLength(ArrB, 2);
ArrB[0] := 'world';
ArrB[1] := 'hello';
if(TArray.SameValues<string>(ArrA, ArrB, TEqualityComparer<string>.Default, True)) then
ShowMessage('Same values and same order')
else if(TArray.SameValues<string>(ArrA, ArrB, TEqualityComparer<string>.Default, False)) then
ShowMessage('Same values but different order')
else
ShowMessage('Different values');
end;
您尝试执行的操作是不可能的,因为开放数组和动态数组与您的代码尝试的方式不兼容。
不过,有一种简单的方法可以实现您想要的效果,即使用简单的递归。像这样:
class function TArray.SameValues<T>(const AValuesA: array of T; AValuesB: array of T; const AComparer: IEqualityComparer<T>; AOrderMatters : Boolean = True) : Boolean;
var
ArrA : TArray<T>;
ArrB : TArray<T>;
i : integer;
begin
//checking sizes
if Length(AValuesA) <> Length(AValuesB) then
begin
Result := False;
Exit;
end;
if not AOrderMatters then
begin
//copying to local arrays
SetLength(ArrA, Length(AValuesA));
TArray.Copy<T>(AValuesA, ArrA, Length(AValuesA));
SetLength(ArrB, Length(AValuesB));
TArray.Copy<T>(AValuesB, ArrB, Length(AValuesB));
//sorting local arrays
TArray.Sort<T>(ArrA);
TArray.Sort<T>(ArrB);
Result := SameValues<T>(ArrA, ArrB, AComparer, True);
Exit;
end;
//comparing elements
for i := 0 to High(AValuesA) do
begin
if not AComparer.Equals(AValuesA[i], AValuesB[i]) then
begin
Result := False;
Exit;
end;
end;
Result := True;
end;
我正在尝试有条件地分配一个本地开放数组变量,以便它指向一个常量开放数组参数:
uses
System.Generics.Collections,
System.Generics.Defaults;
type
TArray = class(System.Generics.Collections.TArray)
public
class function SameValues<T>(const AValuesA: array of T; AValuesB: array of T; const AComparer: IEqualityComparer<T>; AOrderMatters : Boolean = True) : Boolean; overload; static;
end;
...
class function TArray.SameValues<T>(const AValuesA: array of T; AValuesB: array of T; const AComparer: IEqualityComparer<T>; AOrderMatters : Boolean = True) : Boolean;
var
ArrA : TArray<T>;
ArrB : TArray<T>;
i : integer;
begin
//checking sizes
if(Length(AValuesA) <> Length(AValuesB)) then
begin
Result := False;
Exit;
end;
if(AOrderMatters) then
begin
//I don't need to change the arrays, so I could directly point to the open array parameters
ArrA := AValuesA;
ArrB := AValuesB;
end else
begin
//copying to local arrays
SetLength(ArrA, Length(AValuesA));
TArray.Copy<T>(AValuesA, ArrA, Length(AValuesA));
SetLength(ArrB, Length(AValuesB));
TArray.Copy<T>(AValuesB, ArrB, Length(AValuesB));
//sorting local arrays
TArray.Sort<T>(ArrA);
TArray.Sort<T>(ArrB);
end;
//comparing elements
i := 0;
while(i < Length(ArrA)) do
begin
if(not AComparer.Equals(ArrA[i], ArrB[i])) then
begin
Result := False;
Exit;
end;
Inc(i);
end;
Result := True;
end;
编译时,在以下位置引发 E2010 错误:
//I don't need to change the arrays, so I could directly point to the open array parameters
ArrA := AValuesA;
ArrB := AValuesB;
E2010 Incompatible types: 'Dynamic array' and 'array of T'
我试过以下方法:
ArrA := @AValuesA;
ArrB := @AValuesB;
它编译但随后在运行时引发 AV 异常(最重要的是,我不知道这是否是一种安全的方法)。
这是我的测试应用程序代码:
uses
System.Generics.Defaults;
procedure TForm1.FormCreate(Sender: TObject);
var
ArrA : array of string;
ArrB : array of string;
begin
SetLength(ArrA, 2);
ArrA[0] := 'hello';
ArrA[1] := 'world';
SetLength(ArrB, 2);
ArrB[0] := 'world';
ArrB[1] := 'hello';
if(TArray.SameValues<string>(ArrA, ArrB, TEqualityComparer<string>.Default, True)) then
ShowMessage('Same values and same order')
else if(TArray.SameValues<string>(ArrA, ArrB, TEqualityComparer<string>.Default, False)) then
ShowMessage('Same values but different order')
else
ShowMessage('Different values');
end;
您尝试执行的操作是不可能的,因为开放数组和动态数组与您的代码尝试的方式不兼容。
不过,有一种简单的方法可以实现您想要的效果,即使用简单的递归。像这样:
class function TArray.SameValues<T>(const AValuesA: array of T; AValuesB: array of T; const AComparer: IEqualityComparer<T>; AOrderMatters : Boolean = True) : Boolean;
var
ArrA : TArray<T>;
ArrB : TArray<T>;
i : integer;
begin
//checking sizes
if Length(AValuesA) <> Length(AValuesB) then
begin
Result := False;
Exit;
end;
if not AOrderMatters then
begin
//copying to local arrays
SetLength(ArrA, Length(AValuesA));
TArray.Copy<T>(AValuesA, ArrA, Length(AValuesA));
SetLength(ArrB, Length(AValuesB));
TArray.Copy<T>(AValuesB, ArrB, Length(AValuesB));
//sorting local arrays
TArray.Sort<T>(ArrA);
TArray.Sort<T>(ArrB);
Result := SameValues<T>(ArrA, ArrB, AComparer, True);
Exit;
end;
//comparing elements
for i := 0 to High(AValuesA) do
begin
if not AComparer.Equals(AValuesA[i], AValuesB[i]) then
begin
Result := False;
Exit;
end;
end;
Result := True;
end;