2012-04-02 4 views
-8

Если у меня есть список номеров, как этот:получить экстремумы из списка номеров

10,9,8,8,9,7,6,5,4,6,7,8,11,10,12,14,16,20,30,29,28,29,27,25,20,18,15,10,8,5,4,1 

Я хочу, чтобы получить следующие числа (accordint в данном примере): 10,4,30,1

Можно написать функцию, которая получит эти крайности?

Эти цифры являются значениями диаграммы, я хочу получить пики диаграммы.

+3

Какие критерии вы используете, чтобы получить эти цифры? –

+0

Что значит точно крайности? – DarkAjax

+1

Как определяются ваши «крайности»? – knittl

ответ

2

Mine похож на jprofitt's

но я разделил их на пики и спады, так что я могу сделать некоторые вещи с ним.

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

Этот сценарий просто строит точку Out и выбирает вершины и долины, и дать им зеленый и красные соответственно. Смотрите на это как наглядное пособие. : P

graph

<?php 

$plot = array(10,9,8,8,9,7,6,5,4,6,7,8,11,10,12,14,16,20,30,29,28,29,27,25,20,18,15,10,8,5,4,1); 

$res = local_extremes($plot); 

function local_extremes(array $array){ 
    $peaks = array(); 
    $valleys = array(); 

    $peak_keys = array(); 
    $valley_keys = array(); 

    for($i = 0; $i < count($array); $i++){ 
     $more_than_last = $array[$i] > $array[$i-1]; 
     $more_than_next = $array[$i] > $array[$i+1]; 

     $next_is_equal = $array[$i] == $array[$i+1]; 

     if($next_is_equal) continue; 

     if($i == 0){ 
      if($more_than_next){ 
       $peaks[] = $array[$i]; 
       $peak_keys[] = $i; 
      }else{ 
       $valleys[] = $array[$i]; 
       $valley_keys[] = $i; 
      } 
     }elseif($i == (count($array)-1)){ 
      if($more_than_last){ 
       $peaks[] = $array[$i]; 
       $peak_keys[] = $i; 
      }else{ 
       $valleys[] = $array[$i]; 
       $valley_keys[] = $i; 
      } 
     }else{ 
      if($more_than_last && $more_than_next){ 
       $peaks[] = $array[$i]; 
       $peak_keys[] = $i; 
      }elseif(!$more_than_last && !$more_than_next){ 
       $valleys[] = $array[$i]; 
       $valley_keys[] = $i; 
      } 
     } 
    } 

    return array("peaks" => $peaks, "valleys" => $valleys, "peak_keys" => $peak_keys, "valley_keys" => $valley_keys); 
} 
?> 

<style type="text/css"> 
    .container{ 
     position: absolute; 
    } 

    .point{ 
     position: absolute; 
     width: 4px; 
     height: 4px; 
     background: black; 
    } 

    .extreme{ 
     position: absolute; 
     top: 5px; 
    } 

    .extr_low{ 
     background: red; 
    } 

    .extr_high{ 
     background: green; 
    } 
</style> 

<?php 

//Plot 
echo "<div class='container'>"; 
foreach($plot as $key => $point){ 
    $left = ($key*10); 
    $top = 400 - ($point*10); 

    if(in_array($key, $res['peak_keys']) || in_array($key, $res['valley_keys'])){ 
     $extreme = "<div class='extreme'>$point</div>"; 
    }else{ 
     $extreme = ""; 
    } 

    if(in_array($key, $res['peak_keys'])){ 
     $xc = "extr_high"; 
    }elseif(in_array($key, $res['valley_keys'])){ 
     $xc = "extr_low"; 
    }else{ 
     $xc = ""; 
    } 

    echo "<div class='point $xc' style='left: ".$left."px; top: ".$top."px;'>$extreme</div>"; 
} 
echo "</div>"; 

?> 

<table> 
    <tr> 
     <th>&nbsp;</th> 
     <th>Valley</th> 
     <th>Peak</th> 
    </tr> 
    <tr> 
     <th>Lowest</th> 

     <td><?php echo min($res['valleys']); ?></td> 
     <td><?php echo min($res['peaks']); ?></td> 
    </tr> 
    <tr> 
     <th>Highest</th> 
     <td><?php echo max($res['valleys']); ?></td> 
     <td><?php echo max($res['peaks']); ?></td> 
    </tr> 
</table> 
+0

спасибо, мне это нравится :) ... – John

1

Да, для каждого числа в строке вы сравниваете его с боковыми номерами, и вы получили его (это число меньше, чем число до и после). Затем добавьте числа первым и последним числом, и это целое.

Я ожидаю, что это какой-то отсортированный массив.

+0

john vs. john:] все же правильный ответ (хотя он также вернет номер 29) – knittl

0

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

1

Вот псевдо-код для выполнения этого

вход: ListOfNumbers

//Handle exceptional cases 
if listOfNumbers.length == 0 
    return [] 
if listOfNumbers.length == 1 
    return [listOfNumbers[0]] 

//Pre-condition listOfNumbers.length > 1 
extremes = emptyList 
lastNumber = listOfNumbers[0] 
isIncreasing = listOfNumbers[0] < listOfNumbers[1] 
extremes.push(listOfNumbers[0]) 
foreach number in listOfNumbers[1...listOfNumbers.length] 
    if(isIncreasing AND lastNumber > number) 
    extremes.push(lastNumber) 
    isIncreasing = false 
    if(NOT isIncreasing AND lastNumber < number) 
    extremes.push(lastNumber) 
    isIncreasing = true 

extremes.push(listOfNumbers.length-1) 
return extremes 

Я думаю, что это будет делать это, хотя я не проверял это.

+0

Это вернет только глобальный максимум/минимум, а не локальные максимумы и минимумы. – knittl

+0

Спасибо за совет. Я работаю с php – John

+0

Oh. Думаю, я понимаю, что он теперь, макс и минус «волн, создаваемых числами». – Tobias

5

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

<?php 

$array = array(10,9,8,8,9,7,6,5,4,6,7,8,11,10,12,14,16,20,30,29,28,29,27,25,20,18,15,10,8,5,4,1); 

$extremes = array(); 
$last = null; 
$num = count($array); 
for($i=0;$i<$num - 1;$i++) { 
    $curr = $array[$i]; 
    if($last === null) { 
     $extremes[] = $curr; 
     $last = $curr; 
     continue; 
    } 

    //min 
    if($last > $curr && $curr < $array[$i + 1]) { 
     $extremes[] = $curr; 
    } 
    //maxes 
    else if ($last < $curr && $curr > $array[$i + 1]) { 
     $extremes[] = $curr; 
    } 
    if($last != $curr && $curr != $array[$i + 1]) { 
     $last = $curr; 
    } 
} 
//add last point 
$extremes[] = $array[$num - 1]; 

print_r($extremes); 

дает вам результаты (если вы пропустили пару в списке):

Array 
(
    [0] => 10 
    [1] => 8 
    [2] => 9 
    [3] => 4 
    [4] => 11 
    [5] => 10 
    [6] => 30 
    [7] => 28 
    [8] => 29 
    [9] => 1 
) 

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

+0

Вы можете ввести строгий порядок значений ('<' and '>' вместо '> ='/'<='), это вернет только одно дополнительное значение (29) – knittl

+0

Спасибо, теперь я знаю, с чего начать :) .. да, я хочу результаты точно так же, как я писал. Я постараюсь это сделать :) – John

+0

@knittl Я подумал об этом и просто сделал этот способ выбора дизайна, но вы заставили меня подумать об ошибке, которую я не рассматривал. (1, 5, 5, 8) дал бы 5 как минимум/ – jprofitt

3

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

<?php 
define('MSB_MASK', (int)(PHP_INT_MAX + 1)); 
$points = array(0, 0, 1, 0, -1, -2, -2, -3, -4, -3, 0, 1); 
$extrema = getExtrema($points); 

function getExtrema($points) { 
    $extrema = array($points[0]); 
    $limit= count($points)-2; 
    for ($i = 0; $i < $limit; ++$i) { 
     $deltai = $points[$i+1]-$points[$i]; 
     $deltaiplus1 = $points[$i+2]-$points[$i+1]; 
     if (($deltai^$deltaiplus1) & MSB_MASK) 
      $extrema[] = $points[$i+1]; 
    } 
    $extrema[] = $points[$limit+1]; 
    return $extrema; 
} 
?> 

Примечание. Я тестировал немного на ideone.com, это работает, но у него могут быть необнаруженные проблемы. Это должно работать и для поплавков.

Кредит: Это первый производный тест из каждого учебника Исчисления I, слегка адаптированный для дискретных математических вычислений. Мы рассматриваем каждую точку как критическую точку, потому что мы не знаем функции для графика.

Редактировать: После просмотра графика данных на wolframalpha Я думаю, что, возможно, вы просто ищете глобальный максимум и минимум на закрытом интервале плюс конечные точки? Если это так, просто используйте что-то простое, например max($points) и min($points).

Редактировать: У меня никогда не было хорошей возможности использовать xor раньше!

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