函数用于平均Delphi中任何数组的元素

时间:2016-09-16 19:25:58

标签: arrays delphi delphi-6

我们如何在Delphi 6中实现一个函数来平均动态多维数组的所有元素?如:

Function Average(arr:any_array):extended;

其中arr是动态数组,可能包含1个或多个维度。

链接问题:我们如何线性化多维数组?你有什么例子吗?

我问这个是因为我有许多不同的数组,如果可能的话,我必须使用相同的函数进行平均。

2 个答案:

答案 0 :(得分:0)

如果你有一维数组,只需使用位于Mean单位的Math函数。

但对于多维数组,我担心没有可用的功能。主要原因是Delphi以一种特定的方式处理多维数组。

虽然在许多其他编程语言中,多维数组实际上只是一维数组,具有用于访问数组元素的修改机制,其工作方式如下:

Actual Array Item Index = First parameter + (Second parameter * Size of first dimension)

在Delphi中,多维数组表示为由另一个数组引用的多个一维数组,如下所示:

Array of One Dimensional Array

编辑2:正如David在评论中所提到的,这些类型的数组也称为Jagged arraysRagged arrays

为什么这么不同?为什么这么重要?因为来自Delphi中多维数组的那些一维数组不需要具有相同的大小。因此,多维数组中的数据实际上看起来像这样(其中每个X代表一个数组项):

XXXX
XXXXXXX
XXXX
XXXXX

所以我担心你必须为此编写自己的功能。但这不应该那么难。

您需要的是一种迭代数组中每个项目的机制(我打赌您已经在代码中实现了这一点),因此您可以总结数组中所有元素的值。然后将该总和除以数组中元素的数量,以获得所有项目的算术平均值。

编辑3:我不确定您是否可以使用单个代码来遍历所有动态数组。我的意思是,至少你需要知道你的阵列有多少维度。这是必需的,因为为了遍历数组的多个维度,您实际上需要递归遍历表示不同维度的每个单独数组。

用于汇总3D动态数组中元素的代码如下所示:

type
  TDyn3Darray = array of array of array of Single;

implementation

function SumOf3DArray(Dyn3DArray: TDyn3DArray): Single;
var X,Y,Z, a: Integer;
    ArrItem: Single;
begin
  Result := 0;
  SetLength(Dyn3Darray,5,8,40);
  for X := Low(Dyn3Darray) to High(Dyn3Darray) do
  begin
    for Y := Low(Dyn3Darray[X]) to High(Dyn3Darray[X]) do
    begin
      for Z := Low(Dyn3Darray[X,Y]) to High(Dyn3Darray[X,Y]) do
      begin
        Result := Result + Dyn3Darray[X,Y,Z];
      end;
    end;
  end;
end;

我相信您可以自行修改不同维数的代码。

编辑1:对于多维数组的linearizing,我相信你的意思是改变一维数组中的多维数组,你只需复制单独维度的元素并将它们添加到一维数组中。

但这样做只是为了获得所有元素的平均值是不切实际的,因为首先你需要两倍的内存量和第二个,以便将所有元素从多个维度复制到一个你可能会有的首先迭代每个元素。然后你用来计算平均值的任何方法都必须再次遍历所有这些复制的元素,这样就没有充分的理由放慢过程。

如果您有兴趣用一维数组替换多维数组,同时仍然将其元素视为多维数组,请检查我对其他编程语言如何处理多维数组的解释。

请注意,这将要求您通过特殊方法访问此类数组的所有项目,从而导致您与这些数组交互时代码的大量更改。除非您将这些数组包装在具有默认多索引属性的类中,该属性允许您访问数组项。这种方法需要额外的代码来初始化和完成这些类,并且在调整此类数组的大小时需要稍加修改的方法。

答案 1 :(得分:0)

Delphi没有为您提供检查任意动态数组维度的简便方法。实际上,它无法为您传递任意动态数组。但是,在实践中,您通常会遇到一维和二维数组,很少有更高维度的数组。所以你只需编写一些函数:

type
  TDoubleArray1 = array of Double;
  TDoubleArray2 = array of TDoubleArray1;
  TDoubleArray3 = array of TDoubleArray2;

function Mean(const arr: TDoubleArray1): Double; overload;
function Mean(const arr: TDoubleArray2): Double; overload;
function Mean(const arr: TDoubleArray3): Double; overload;

像这样实施:

function Mean(const arr: TDoubleArray1): Double;
var
  i: Integer;
begin
  Result := 0.0;
  for i := low(arr) to high(arr) do
    Result := Result + arr[i];
  Result := Result / Length(arr);
end;

function Mean(const arr: TDoubleArray2): Double;
var
  i, j, N: Integer;
begin
  Result := 0.0;
  N := 0;
  for i := low(arr) to high(arr) do
    for j := low(arr[i]) to high(arr[i]) do
    begin
      Result := Result + arr[i,j];
      inc(N);
    end;
  Result := Result / N;
end;

function Mean(const arr: TDoubleArray3): Double;
var
  i, j, k, N: Integer;
begin
  Result := 0.0;
  N := 0;
  for i := low(arr) to high(arr) do
    for j := low(arr[i]) to high(arr[i]) do
      for k := low(arr[i,j]) to high(arr[i,j]) do
      begin
        Result := Result + arr[i,j,k];
        inc(N);
      end;
  Result := Result / N;
end;

如果你真的需要比这更高的尺寸,我会感到惊讶,但它很容易添加。

有些观点:

  • 我使用Double而不是Extended是出于性能原因,因为后者的大小为10会导致大量错误对齐的内存访问。如果你不能让自己避免Extended,你可以随时调整上面的代码。
  • 您可能会发现使用RTTI编写单个函数的低级方法可以迭代任何动态数组,但RTTI可能会影响性能。我个人认为走这条路并没有任何意义。使用这样的一些功能就可以完成。