我有几个变量的函数f
(例如3个变量f(x,y,z)
)。我想计算每个变量范围的函数结果并将它们存储在列表中。对于3个变量,这可能如下所示:
procedure LoopOver3Dimensions;
type
TListItem=record
x, y, z: Real;
CalculationResult: Real;
end;
var
List: TList<TListItem>;
NewListItem: TListItem;
i, j, k: Integer;
x, y, z: Real;
xStart, yStart, zStart: Real;
xEnd, yEnd, zEnd: Real;
NumberOfValuesToCalculateForDimension0: Integer;
NumberOfValuesToCalculateForDimension1: Integer;
NumberOfValuesToCalculateForDimension2: Integer;
begin
//set xStart, xEnd, NumberOfValuesToCalculateForDimension0 etc here
for i := 0 to NumberOfValuesToCalculateForDimension0 do
begin
x:=xStart+i*Abs(xEnd-xStart)/(NumberOfValuesToCalculateForDimension0-1);
for j := 0 to NumberOfValuesToCalculateForDimension1 do
begin
y:=yStart+j*Abs(yEnd-yStart)/(NumberOfValuesToCalculateForDimension1-1);
for k := 0 to NumberOfValuesToCalculateForDimension2 do
begin
z:=zStart+k*Abs(zEnd-zStart)/(NumberOfValuesToCalculateForDimension2-1);
NewListItem.x:=x;
NewListItem.y:=y;
NewListItem.z:=z;
NewListItem.CalculationResult:=DoCalculation(x, y, z);
List.Add(NewListItem);
end;
end;
end;
end;
我当然可以以相同的方式为超过3个维度(例如20个维度)编程,但它会变得非常麻烦,因为所有内容都是硬编码的,所以我无法在运行时更改维度数。
这样做的最佳方式是什么?
答案 0 :(得分:2)
正如评论中所讨论的,为了支持任意数量的参数,最好使用可变长度的数组而不是参数。这是因为该语言对可变长度参数列表没有很大的支持。
将所有参数打包为数组后,您将面临生成所有可能的组合。这不是一个完全简单的任务。我将在i
到{$APPTYPE CONSOLE}
uses
System.SysUtils;
procedure IterMultiDim(const N: array of Integer; const Proc: TProc<TArray<Integer>>);
var
dim: Integer;
Current: TArray<Integer>;
begin
SetLength(Current, Length(N));
while Current[high(N)]<N[high(N)] do begin
Proc(Current);
// increment state
dim := 0;
while dim<=high(N) do begin
inc(Current[dim]);
if Current[dim]=N[dim] then begin
if dim<high(N) then begin
Current[dim] := 0;
end;
end else begin
break;
end;
inc(dim);
end;
end;
end;
procedure WriteIntArray(Arr: TArray<Integer>);
var
i: Integer;
begin
for i := 0 to high(Arr) do begin
Write(Arr[i]);
if i<high(Arr) then begin
Write(', ');
end;
end;
Writeln;
end;
procedure Main;
begin
IterMultiDim([2, 3, 4], WriteIntArray);
end;
begin
try
Main;
except
on E: Exception do begin
Writeln(E.ClassName, ': ', E.Message);
end;
end;
Readln;
end.
范围内,而不是使用实际值,我将向您展示如何在每个维度为整数值的情况下执行此操作,其中money1
是维度索引。一旦你可以迭代所有这些组合,你就可以轻松扩展到生成真正的价值。
基本概念是维持当前迭代值,该值递增。第一个维度是循环的最内层。当它达到其最大值时,它返回到零并且下一个外部维度递增。等等。以下是一些示例代码:
Jlabel
<强>输出:强>
0, 0, 0 1, 0, 0 0, 1, 0 1, 1, 0 0, 2, 0 1, 2, 0 0, 0, 1 1, 0, 1 0, 1, 1 1, 1, 1 0, 2, 1 1, 2, 1 0, 0, 2 1, 0, 2 0, 1, 2 1, 1, 2 0, 2, 2 1, 2, 2 0, 0, 3 1, 0, 3 0, 1, 3 1, 1, 3 0, 2, 3 1, 2, 3
这种技术可以用各种方式包裹起来。例如,它可以封装在for / in枚举器中,这将使更高的可读性成为可能。
答案 1 :(得分:0)
受David的方法启发,我提出了另一种解决方案:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
procedure IterMultiDim(const NumberOfCalculationsPerDimension: TArray<Integer>; const Proc: TProc<TArray<Integer>>);
function ModInc(const MaxNumber: Integer; var AValue: Integer): Boolean;
begin
Inc(AValue);
if AValue>MaxNumber then
begin
AValue:=0;
Result:=true; //carry
end
else
begin
Result:=false; //no carry
end;
end;
var
NumberOfDimensions: Integer;
CurrentIndices: TArray<Integer>;
i, j: Integer;
TotalNumberOfCalculations: Integer;
Carry: Boolean;
begin
NumberOfDimensions:=Length(NumberOfCalculationsPerDimension);
SetLength(CurrentIndices, NumberOfDimensions);
TotalNumberOfCalculations:=1;
for i := 0 to NumberOfDimensions-1 do
begin
TotalNumberOfCalculations:=TotalNumberOfCalculations*NumberOfCalculationsPerDimension[i];
end;
for i := 0 to TotalNumberOfCalculations-1 do
begin
Proc(CurrentIndices);
Carry:=true;
for j := 0 to NumberOfDimensions-1 do
begin
if Carry then
begin
Carry:=ModInc(NumberOfCalculationsPerDimension[j]-1, CurrentIndices[j]);
end;
end;
end;
end;
procedure WriteIntArray(Arr: TArray<Integer>);
var
i: Integer;
S: string;
begin
S:='';
for i := 0 to High(Arr) do
begin
S:=S+Arr[i].ToString+' ';
end;
Writeln(S);
end;
procedure Main;
begin
IterMultiDim([3, 4, 2], WriteIntArray);
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.