Вычислить медиану


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

<?php
private function calculateMedian($aValues) {
    $aToCareAbout = array();
    foreach ($aValues as $mValue) {
        if ($mValue >= 0) {
            $aToCareAbout[] = $mValue;
        }
    }
    $iCount = count($aToCareAbout);
    sort($aToCareAbout, SORT_NUMERIC);
    if ($iCount > 2) {
        if ($iCount % 2 == 0) {
            return ($aToCareAbout[floor($iCount / 2) - 1] + $aToCareAbout[floor($iCount / 2)]) / 2;
        } else {
            return $aToCareAbout[$iCount / 2];
        }
    } elseif (isset($aToCareAbout[0])) {
        return $aToCareAbout[0];
    } else {
        return 0;
    }
}


18024
25
задан 26 января 2011 в 12:01 Источник Поделиться
Комментарии
3 ответа

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

Кстати я бы сделал это.

Создать array_median() функции в глобальной области видимости (или статического метода) такой:

/**
* Adapted from Victor T.'s answer
*/
function array_median($array) {
// perhaps all non numeric values should filtered out of $array here?
$iCount = count($array);
if ($iCount == 0) {
throw new DomainException('Median of an empty array is undefined');
}
// if we're down here it must mean $array
// has at least 1 item in the array.
$middle_index = floor($iCount / 2);
sort($array, SORT_NUMERIC);
$median = $array[$middle_index]; // assume an odd # of items
// Handle the even case by averaging the middle 2 items
if ($iCount % 2 == 0) {
$median = ($median + $array[$middle_index - 1]) / 2;
}
return $median;
}

Таким образом, мы, как правило, доступны все функции назначения, с указанием согласуется с основными функциями PHP.

И ваш метод будет выглядеть

/**
* The name should probably be changed, to reflect more your business intent.
*/
private function calculateMedian($aValues) {
return array_median(
array_filter(
$aValues,
function($v) {return (is_numeric($v) && $v >= 0);}
// You can skip is_numeric() check here, if you know all values in $aValues are actually numeric
)
);
}

Либо в calculateMedian() или в код, который вызывает это, вы должны заботиться о поимке DomainException , что может быть брошен, если массив пуст)

19
ответ дан 26 января 2011 в 08:01 Источник Поделиться

Мне интересно, если вы можете просто сжать выше на этот:

private function calculateMedian($aValues) {
$aToCareAbout = array();
foreach ($aValues as $mValue) {
if ($mValue >= 0) {
$aToCareAbout[] = $mValue;
}
}
$iCount = count($aToCareAbout);
if ($iCount == 0) return 0;

// if we're down here it must mean $aToCareAbout
// has at least 1 item in the array.
$middle_index = floor($iCount / 2);
sort($aToCareAbout, SORT_NUMERIC);
$median = $aToCareAbout[$middle_index]; // assume an odd # of items

// Handle the even case by averaging the middle 2 items
if ($iCount % 2 == 0)
$median = ($median + $aToCareAbout[$middle_index - 1]) / 2;

return $median;
}

Я не пишу на PHP, но глядя на онлайн руководство для графа:


функция count() может возвращать 0 для переменной
это не набор, но может еще и вернуться
0 для переменной, которая была
инициализируется пустой массив. Использовать
isset() и проверить, если переменная имеет значение.

Но в вашем случае, функция не заботится, является ли массив пустым или переменной не задано -- 0 возвращается в обоих случаях. Проверив, что count возвращает мы могли устранить некоторые если филиалы.

5
ответ дан 26 января 2011 в 03:01 Источник Поделиться

Лично это способ, которым я хотел бы построить функцию:

function calculateMedian($Values)
{
//Remove array items less than 1
$Values = array_filter($Values,array($this,"callback"));

//Sort the array into descending order 1 - ?
sort($Values, SORT_NUMERIC);

//Find out the total amount of elements in the array
$Count = count($Values);

//Check the amount of remainders to calculate odd/even
if($Count % 2 == 0)
{
return $Values[$Count / 2];
}

return (($Values[($Count / 2)] + $Values[($Count / 2) - 1]) / 2);
}

Какие изменения я сделал?


  • Я использовал меньше переменных, переписав $значений , где это необходимо

  • Снижение условного высказывания к 1* от 2

  • Сделал код более читаемым и понятным.

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

    • общественные функции обратного вызова($значение)
      {
      возвращаемое значение $ > 0;
      }


  • К сожалению, так как "родная" функция пустой фактически языковая конструкция его не является допустимым обратного вызова, вы можете использовать, однако, вернуться !пустой($значение); в ваш метод обратного вызова, чтобы удалить другие органы, такие как значение null,ложь и т. д.

  • Это может быть удалены, как указано, и размещены за пределами функции.

*Примечание: Я бы посоветовал вам иметь какой-то линейный массив проверить, чтобы убедиться, что массивы на основе целочисленного индекса, как наш код говорит, линейный проверяем, можно сделать вот так:

if(array_keys($Values) !== range(0,($Count-1)))
{
return null;
}

это будет добавить после $рассчитывать значение и вступают в игру.

Пример тест, который я использовал, чтобы проверить это:

$values = array(
0,4,7,5,6,9,5,3,2,7,5,6,4,3,7
);
echo calculateMedian($values);

что вылилось в правильный ответ 5

1
ответ дан 26 января 2011 в 06:01 Источник Поделиться