I'm trying to conditionally assign a local open array variable in order it points to a const 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;
On compiling, it raises E2010 error at:
//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'
I've tried the following:
ArrA := @AValuesA;
ArrB := @AValuesB;
It compiles but then it raises AV exception at runtime (and most of all, I don't know if it would be a safe approach).
Here is my test application code:
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;
CodePudding user response:
What you are trying to do is not possible because open arrays and dynamic arrays are not compatible in the way that your code attempts.
There is an easy way to achieve what you want though. You can use a simple recursion to achieve what you need. Like this:
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;