2011-12-24 59 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