简体   繁体   English

对Delphi中任何数组的元素求平均的函数

[英]Function to average elements of any array in Delphi

How can we implement a function to average all elements of a dynamic multidimensional array in Delphi 6? 我们如何在Delphi 6中实现一个函数来平均动态多维数组的所有元素? Such as: 如:

Function Average(arr:any_array):extended;

Where arr is a dynamic array and may have 1 or more dimensions. 其中arr是动态数组,可以具有1个或多个维度。

Linked question: how can we linearize a multidimension array? 链接的问题:我们如何线性化多维数组? Do you have any example? 你有什么例子吗?

I ask this because I have many different arrays which I must average, if possible, with the one same function. 我之所以这样问,是因为我有许多不同的数组,如果可能的话,我必须使用一个相同的函数求平均值。

If you have one dimensional array you can simply use Mean function located in Math unit. 如果您有一维数组,则可以简单地使用Math单元中的Mean函数。

But for multidimensional array I'm afraid there is no already available function. 但是对于多维数组,恐怕还没有可用的函数。 The main reason is that Delphi treats multidimensional arrays in a rather specific way. 主要原因是Delphi以相当特定的方式处理多维数组。

While in many other programming languages multidimensional array are in fact just one dimensional array with modified mechanism for accessing array elements which works something like this: 虽然在许多其他编程语言中,多维数组实际上只是具有改进机制的一维数组,用于访问数组元素的工作原理如下:

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

In Delphi multidimensional arrays are represented as multiple one dimensional array referenced by another array like so: 在Delphi中,多维数组表示为由另一个数组引用的多个一维数组,如下所示:

Array of One Dimensional Array

EDIT 2: As mentioned by David in his comment these type of arrays are also known as Jagged arrays or Ragged arrays . 编辑2:正如David在他的评论中提到的,这些类型的数组也称为Jagged arraysJagged arrays Ragged arrays

Why is this so different? 为什么如此不同? Why is it so important? 为什么这么重要? Because those One Dimensional Arrays that from multidimensional array in Delphi don't need to be of the same size. 因为来自Delphi中多维数组的那些一维数组不必具有相同的大小。 So data in your multidimensional array can actually look like this (where each X represents one array item): 因此,多维数组中的数据实际上可以如下所示(其中每个X代表一个数组项):

XXXX
XXXXXXX
XXXX
XXXXX

So I'm afraid you will have to write your own function for this. 因此,恐怕您将为此编写自己的函数。 But that should not be so hard. 但这不应该那么难。

All you need is a mechanism to iterate through every item in your arrays (I bet you have this already implemented in your code somewhere) so you can sum up the value of all elements in your arrays. 您需要的是一种遍历数组中每个项目的机制(我敢打赌,您已经在代码中的某个地方实现了该功能),以便可以总结数组中所有元素的值。 And then you divide that sum with the number of elements in your arrays in order to get the arithmetical average of all items. 然后,将总和除以数组中元素的数量,以获得所有项的算术平均值。

EDIT 3: I'm not sure if you could have single code to iterate through all of your dynamic arrays. 编辑3:我不确定您是否可以有一个代码来遍历所有动态数组。 I mean at least you need to know how many dimensions does your array have. 我的意思是至少您需要知道数组有多少个维度。 This is required because for iterating through multiple dimensions of an array you actually need to recursively iterate through each separate array that represents separate dimensions. 这是必需的,因为要遍历数组的多个维度,您实际上需要递归地遍历代表不同维度的每个单独的数组。

The code for summing up elements in a 3D dynamic array would look like this: 用于汇总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;

I believe you will be capable to modify the code accordingly for different number of dimensions yourself. 我相信您将能够自己修改不同数量的尺寸的代码。


EDIT 1: As for linearizing of multidimensional arrays in which I believe you mean changing the multidimensional array in one dimensional array you would just copy elements of separate dimensions and add them into one dimensional array. 编辑1:至于多维数组的linearizing ,我相信您的意思是更改一维数组中的多维数组,您只需复制单独维的元素并将它们添加到一维数组中即可。

But doing that just in order to get average value of all elements would not be practical because for first you would need double the amount of memory and as second in order to copy all the elements from multiple dimension into one you would probably have to iterate through every element in the first place. 但是这样做只是为了获得所有元素的平均值是不切实际的,因为首先您需要将内存量增加一倍,其次才能将所有元素从多维复制到一个元素中,您可能必须遍历每个元素都放在首位。 And then whatever method would you use for calculating average value would also have to iterate through all those copied elements again and thus just slowing down the process for no good reason. 然后,无论使用哪种方法来计算平均值,也都必须再次遍历所有这些复制的元素,从而无缘无故地拖慢了整个过程。

And if you are interested in replacing multidimensional arrays with one dimensional arrays while still threating its elements as if they are in multidimensional array check my explanation of how some other programming languages treat multidimensional array. 并且,如果您有兴趣用一维数组替换多维数组,同时又像多维数组一样威胁其元素,请查看我对其他编程语言如何处理多维数组的解释。

NOTE that this would require you accessing all items of such arrays through special methods and will thus result in large changes of your code where you interact with these arrays. 请注意,这将要求您通过特殊方法访问此类数组的所有项目,从而在与这些数组进行交互的地方导致代码的重大更改。 Unless if you would wrap these arrays in a class with default multi indexed property that will allow you accessing the array items. 除非您将这些数组包装在具有默认多索引属性的类中,否则它将允许您访问数组项。 Such approach would require additional code for initialization and finalization of such classes and require a slightly modified approach when resizing of such arrays. 这种方法将需要用于此类初始化和终结的附加代码,并且在调整此类数组的大小时需要稍作修改的方法。

Delphi does not provide easy ways for you to inspect the dimensions of an arbitrary dynamic array. Delphi没有提供简单的方法来检查任意动态数组的维。 Indeed it provides no means for you to pass around an arbitrary dynamic array. 实际上,它没有为您提供传递任意动态数组的方法。 However, in practice, you will encounter one and two dimensional arrays commonly, and seldom anything of higher dimensions. 但是,在实践中,通常会遇到一维和二维数组,很少会遇到更高维的数组。 So you need to write only a handful of functions: 因此,您只需要编写一些函数:

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;

Implement like this: 像这样实现:

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;

It would astound me if you really needed higher dimensions than this, but it is easy to add. 如果确实需要更大的尺寸,这会让我感到惊讶,但是添加起来很容易。

Some points: 一些要点:

  • I'm using Double rather than Extended for reasons of performance, as the latter has a size of 10 which leads to a lot of mis-aligned memory access. 由于性能原因,我使用Double而不是Extended ,因为后者的大小为10,这会导致大量未对齐的内存访问。 If you cannot bring yourself to avoid Extended you can readily adapt the code above. 如果您无法避免Extended ,可以随时改写上面的代码。
  • You could probably find low-level methods using RTTI to write a single function that iterates over any dynamic array, however, the RTTI would likely impact performance. 您可能会发现使用RTTI编写可在任何动态数组上进行迭代的单个函数的底层方法,但是RTTI可能会影响性能。 I personally don't see any point in going that route. 我个人认为那条路线没有任何意义。 Use a handful of functions like this and be done. 使用一些这样的功能即可完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM