Php 从数字列表中获取极值
如果我有一个这样的数字列表:Php 从数字列表中获取极值,php,numbers,Php,Numbers,如果我有一个这样的数字列表: 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 我想得到以下数字(根据本例):10,4,30,1 是否可以编写一个函数来获得这些极端值? 这些数字是图表的值,我想得到图表的峰值。是的,对于每一行中的数字,您将其与边数进行比较,就得到了边数(您需要该数字小于前后的数字)。然后把第一个数字和最后一个数字相加,它就完整了 我希望它是某种排序的数组。从数字数组
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
我想得到以下数字(根据本例):10,4,30,1
是否可以编写一个函数来获得这些极端值?
这些数字是图表的值,我想得到图表的峰值。是的,对于每一行中的数字,您将其与边数进行比较,就得到了边数(您需要该数字小于前后的数字)。然后把第一个数字和最后一个数字相加,它就完整了
我希望它是某种排序的数组。从数字数组中获取第一个和最后一个数字,然后对数组排序并获取与上次结果不同的第一个和最后一个数字。你会得到一个和你的例子一样的结果 下面是执行此操作的伪代码 输入:列表编号
//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
//处理异常情况
如果listofNumber.length==0
返回[]
如果listofNumber.length==1
返回[ListofNumber[0]]
//前置条件列表OfNumbers.length>1
极端=空列表
lastNumber=ListOfNumber[0]
IsIncreating=ListofNumber[0]number)
极限。推送(最后一个数字)
i递增=错误
if(非递增且lastNumber<数字)
极限。推送(最后一个数字)
i递增=真
极限。推送(列表编号。长度-1)
回归极端
我认为这可以做到,尽管我还没有测试过。我没有测试过这么多,任何分数低于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);
如果你想让它完全像你的列表一样,你必须对数据应用一些平滑处理,或者对检测应用一些公差。一阶导数测试的一个变体,用于识别局部极值,识别delta符号从一个间隔交替到下一个间隔的点。如果增量从正到负,这些点将是最大值,如果增量从负到正,这些点将是最小值,但对于您的使用来说,这似乎并不重要。另外,加入端点,因为间隔被认为是开放的,并且您似乎希望将其包括在内
<?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上做了一些测试,它可以工作,但可能有未检测到的问题。这同样适用于浮动
学分:这是我每一本微积分教科书中的一阶导数测试,只对离散数学做了少许修改。我们将每个点都视为临界点,因为我们不知道图的函数
编辑:在看了一个数据图之后,我想也许你只是在寻找闭合区间上的全局最大值和最小值,加上端点?如果是这样,只需使用一些简单的方法,比如max($points)
和min($points)
编辑:我以前从未有过使用xor的好机会 我的类似于
但是我把它们分为山峰和峡谷,这样我可以用它做更多的事情
我认为他的循环比我的循环干净得多,但我只是想亲自测试一下。不要评判米伊 这个脚本只是绘制出点,并选择峰和谷,分别给它们绿色和红色。将其视为视觉辅助工具:P
<?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> </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>
.集装箱{
位置:绝对位置;
}
.点{
位置:绝对位置;
宽度:4px;
高度:4px;
背景:黑色;
}
.极端{
位置:绝对位置;
顶部:5px;
}
.extr_low{
背景:红色;
}
.Extra_high{
背景:绿色;
}
你用什么标准来获得这些数字?你所说的极端到底是什么意思?你的“极端”是如何定义的?我假设你给出的抽取示例有某种形式的模式。愿意分享吗?你是说本地最小值和最大值吗?这将只返回全局最大值/最小值,而不是本地最大值和最小值。我和phpOh一起工作。我想我现在明白他在追求什么了,“数字创造的波浪”的最大值和最小值。john vs.john:]尽管答案正确(虽然它也会返回数字29),但你可以强制执行严格的值排序(
而不是=
/谢谢,现在我知道从哪里开始了:)。。是的,我想要的结果和我写的一模一样。我会试着去做:)@knittl我考虑过这一点,只是把这种方式作为一种设计选择,但你让我想到了一个我没有考虑过的bug。(1,5,5,8)将以5作为最小/最大值谢谢,我喜欢:)。。。
<?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> </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>