2011-12-24 60 views
4

PHP是否具有用于不规则步长范围的现有功能,是否有通用的解决方案来提供此功能,或者如何优化以下功能?生成一个范围不规则的步骤。优化

第一个函数是我关心的函数。第二个函数是一个真实世界用例,它生成一个数组以填充为HTML输出选择下拉列表的函数的值。

<?php 

function range_multistep($min, $max, Array $steps, $jmp = 10) { 
    $steps = array_unique($steps); 
    sort($steps, SORT_NUMERIC); 

    $bigstep = ($jmp > 0) ? $jmp : $jmp * -1; 

    $e = ($min > 0) ? floor(log($min, $bigstep)) : 0; 
    for (; ; $e++) { 
     foreach ($steps as $step) { 
      $jump = pow($bigstep, $e); 
      $num = $step * $jump; 
      if ($num > $max) { 
       break 2; 
      } elseif ($num >= $min) { 
       $arr[] = $num; 
      } 
     } 
    } 

    $arr = array_unique($arr); 
    sort($arr, SORT_NUMERIC); 

    return $arr; 
} 

function prices() { 
    $price_steps = range_multistep(50, 100000, array(5, 10, 25)); 

    $prev_step = 0; 
    foreach ($price_steps as $price) { 
     $price_str = '$' . $prev_step . ' - $' . ($price - 1); 
     $price_arr[] = $price_str; 
     $prev_step = $price; 
    } 
    $price_arr[] = '$' . end($price_steps) . "+"; 

    return $price_arr; 
} 

print_r(prices()); 

先前的结果:

Array 
(
    [0] => $0 - $49 
    [1] => $50 - $99 
    [2] => $100 - $249 
    [3] => $250 - $499 
    [4] => $500 - $999 
    [5] => $1000 - $2499 
    [6] => $2500 - $4999 
    [7] => $5000 - $9999 
    [8] => $10000 - $24999 
    [9] => $25000 - $49999 
    [10] => $50000 - $99999 
    [11] => $100000+ 
) 
+0

有一件事情需要思考,最好是根据最小/最大生成一个范围,并通过foreach在一段时间内运行该数组? – 2011-12-29 10:31:11

回答

1

for循环中的$e递增器更多的是无限循环的while(1)

因此,不要使用pow()中的增量器,只需在每次迭代中乘以一次即可自行执行pow。调用pow()可能会非常昂贵,因此自己计算pow会更好地将乘法分配到每次迭代。

编辑:以下是您的函数的一个变种,它在迭代中分配pow()计算。此外,它执行更适当的变量初始化(例如未设置返回值),通知$min$max已交换并更正该错误,使用abs而不是您的三元,如果为log()给出无效值,则将引发异常,重命名一些变量并添加$num到返回值为键首先在年底做足array_unique操作:

/** 
* @param int $min 
* @param int $max 
* @param array $steps 
* @param int $jmp 
* @return array range 
*/ 
function range_multistep($min, $max, Array $steps, $jmp = 10) { 
    $range = array(); 
    if (!$steps) return $range; 

    if ($min < $max) { 
     trigger_error(__FUNCTION__.'(): Minima and Maxima mal-aligned.', E_USER_NOTICE); 
     list($max, $min) = array($min, $max); 
    } 

    $steps = array_unique($steps); 
    sort($steps, SORT_NUMERIC); 

    $bigstep = abs($jmp); 
    if ($bigstep === 0) { 
     throw new InvalidArgumentException(sprintf('Value %d is invalid for jmp', $jmp)); 
    } 

    $initExponent = ($min > 0) ? floor(log($min, $bigstep)) : 0; 

    for ($multiplier = pow($bigstep, $initExponent); ; $multiplier *= $bigstep) { 
     foreach ($steps as $step) { 
      $num = $step * $multiplier; 
      if ($num > $max) { 
       break 2; 
      } elseif ($num >= $min) { 
       $range[$num] = 1; 
      } 
     } 
    } 

    $range = array_keys($range); 
    sort($range, SORT_NUMERIC); 

    return $range; 
} 

在你觉得实验的情况下,它也可以把两个回路(for + foreach)合为一体,但代码的可读性不会从中受益:

for(
    $multiplier = pow($bigstep, $initExponent), 
    $step = reset($steps) 
     ; 
    $num = $step * $multiplier, 
    $num <= $max 
     ; 
    # infinite array iterator: 
    ($step=next($steps))?: 
    (
     $step=reset($steps) 
     # with reset expression: 
     AND $multiplier *= $bigstep 
    ) 
){ 
    if ($num >= $min) 
     $range[$num] = 1; 
} 

我认为,如果你小心不要重复使用变量(比如函数参数),并让它们更好地读取名称,改进就来自它。

+0

'$ jmp'和'$ jump'是两个令人困惑的单独变量。 '$ min!= min($ min,$ max)'比$ min <$ max'更好吗?如果是这样,为什么? – 2011-12-29 21:50:04

+0

不是真的;),现在按照你的要求,我会选择'$ min <$ max';) - 我最后很快完成了这部分,并尝试了其他的东西,所以只是一个人工制品。我完全删除了'$ jump',将检查答案的措辞,这是我的错误。 – hakre 2011-12-29 22:08:26

+0

此外,参数中的类型转换数组将不会触发错误或给我们一个数组,这将使我们永远不会执行'if(!$ steps)'后面的代码。也许'if(empty($ steps))'会更合适。 – 2011-12-29 23:07:06

2

反复另外最好用乘法代替,重复乘法最好通过提高对权力更换 - 你所做的一切。

我在这里没有看到任何需要改进的地方,假设您在面对$jmp = 1$min >= $max表现不佳的输入时不需要“防弹”行为。

+0

防弹是没有必要的,但它会很好,让它感觉完整。 – 2011-12-27 13:56:15