algorithm - 遍历多个维度

标签 algorithm loops delphi iteration

我有一个包含多个变量的函数 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 个维度)进行编程,但这会变得非常麻烦,而且由于所有内容都是硬编码的,我无法在运行时更改维度的数量。

执行此操作的最佳方法是什么?

最佳答案

正如评论中所讨论的,为了支持任意数量的参数,最好使用可变长度的数组而不是参数。这是因为该语言对可变长度参数列表没有很好的支持。

一旦将所有参数打包为一个数组,您就会面临生成所有可能组合的问题。这不是一项完全简单的任务。我将不使用实际值,而是向您展示如何使用整数值的每个维度执行此操作,范围为 0N[i]-1 ,其中 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.

输出:

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 枚举器中,这样可以提高可读性。

关于algorithm - 遍历多个维度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44096698/

相关文章:

c - 如何使用 C 在大文本中查找短语?

python - 为什么不分配给循环变量修改原始列表?如何循环分配回列表?

.net - 德尔福和.NET。使用 Visual Studio

python - 如何以 Pythonic 方式停止 try/except 中 for 循环的代码执行?

delphi - 为什么TForm的_release不调用析构函数?

macos - 在 OS X 上运行 Delphi 10 Seattle 应用程序时出现 Dylib 版本错误

algorithm - 找到矩阵中最后一个像螺旋一样行走的正方形

c - 如何解析 C 中的十进制 UUID 字符串?

c# - 缓存函数结果

javascript - NodeJs 使用 async 和 for 循环下载