2016-09-16 2 views
0

Как мы можем реализовать функцию для усреднения всех элементов динамического многомерного массива в Delphi 6? Такие, как:Функция для средних элементов любого массива в Delphi

Function Average(arr:any_array):extended; 

Где arr представляет собой динамический массив, и может иметь 1 или более измерений.

Связанный вопрос: как мы можем линеаризовать массив многомерных измерений? У вас есть пример?

Я спрашиваю об этом, потому что у меня есть много разных массивов, которые я должен усреднить, если возможно, с одной и той же функцией.

+0

Массивы с различными размерами потребуют некоторой магии или типа обертки. Что вы подразумеваете под линеаризацией? –

+0

Вы также не хотите использовать Extended, потому что он имеет тенденцию быть плохо выровненным и иметь работу с мусором. –

ответ

0

Если у вас есть один размерный массив, вы можете просто использовать функцию Mean, расположенную в Math единицах.

Но для многомерного массива я боюсь, что уже нет функции. Основная причина в том, что Delphi рассматривает многомерные массивы довольно определенным образом.

Хотя во многих других языках программирования многомерный массив, на самом деле только один одномерный массив с модифицированным механизмом для доступа к элементам массива, который работает что-то вроде этого:

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

В Delphi многомерных массивов представлены в виде множественного одного мерный массив ссылается другой массив следующим образом:

Array of One Dimensional Array

EDIT 2: Как упомянуто D жадный в своем комментарии, эти типы массивов также известны как Jagged arrays или Ragged arrays.

Почему это так отличается? Почему это так важно? Потому что те одномерные массивы, что из многомерного массива в Delphi не должны быть одного размера. Таким образом, данные в вашем многомерном массиве на самом деле может выглядеть следующим образом (где каждый X представляет собой один элемент массива):

XXXX 
XXXXXXX 
XXXX 
XXXXX 

Так что я боюсь, вам придется написать свою собственную функцию для этого. Но это не должно быть так сложно.

Все, что вам нужно, это механизм для повторения каждого элемента в ваших массивах (я уверен, вы уже это уже реализовали в своем коде), чтобы вы могли суммировать значение всех элементов в ваших массивах. И тогда вы разделите эту сумму на количество элементов в своих массивах, чтобы получить среднее арифметическое всех предметов.

EDIT 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; 

Я считаю, что вы будете способны изменить код соответственно для различного числа измерений самостоятельно.


EDIT 1: Что касается linearizing многомерных массивов, в которых я верю, что вы имеете в виду изменение многомерного массива в одномерный массив вы бы просто скопировать элементы отдельных размеров и добавить их в одномерный массив.

Но делать это просто для того, чтобы получить среднее значение всех элементов, было бы нецелесообразно, потому что для начала вам понадобилось бы удвоить объем памяти и как второй, чтобы скопировать все элементы из нескольких измерений в один, вы, вероятно, должны проходить через каждый элемент в первую очередь. И тогда любой метод, который вы использовали бы для вычисления среднего значения, также должен был бы повторить все эти скопированные элементы и таким образом просто замедлить процесс без уважительной причины.

И если вы заинтересованы в замене многомерных массивов на одномерные массивы, в то же время создавая свои элементы, как если бы они находились в многомерном массиве, проверьте мое объяснение того, как некоторые другие языки программирования обрабатывают многомерный массив.

Обратите внимание, что это потребует от вас доступа ко всем элементам таких массивов с помощью специальных методов и, таким образом, приведет к большим изменениям вашего кода, где вы будете взаимодействовать с этими массивами. Если вы не поместили бы эти массивы в класс со значением по умолчанию с несколькими индексами, что позволит вам получить доступ к элементам массива. Такой подход потребует дополнительного кода для инициализации и доработки таких классов и требует небольшого изменения подхода при изменении размера таких массивов.

+0

FWIW Delphi не имеет настоящих многомерных динамических массивов и вместо этого использует ** зубчатые ** массивы. –

+0

@DavidHeffernan Вы правы. И я должен признать, что до сегодняшнего дня я не видел, чтобы их так называли. – SilverWarior

+0

Вы сказали: «Все, что вам нужно, это механизм для итерации каждого элемента в ваших массивах (я уверен, вы уже это уже реализовали в своем коде), чтобы вы могли суммировать значение всех элементов в ваших массивах». Правильно.Как это сделать, поскольку существуют динамические массивы? Как определить dims (dim/size) (динамического) массива, переданного моей функции, поэтому я могу повторять их? Помните: у меня много разных массивов и вы хотите использовать одну и ту же функцию для всех из них. –

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, что приводит к большому количеству MIS-выровненные доступа к памяти. Если вы не можете заставить себя избегать Extended, вы можете легко адаптировать код выше.
  • Возможно, вы найдете методы низкого уровня, используя RTTI, чтобы написать одну функцию, которая выполняет итерацию по любому динамическому массиву, однако RTTI, вероятно, повлияет на производительность. Я лично не вижу смысла в этом маршруте. Используйте несколько функций, подобных этому, и сделайте это.
+0

Я уже определил 5 перегруженных функций для 1 ... 5 dims, но я подумал, что это более элегантный способ. Спасибо, в любом случае. PS действительно ли это разница между использованием удвоений или расширений? –

+0

Я думаю, что нет элегантного желания. И да, расширенный продюсер часто очень плохо –

Смежные вопросы