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 :(得分:2)
重复加法最好用乘法代替,重复乘法最好用提升到幂来代替 - 你已经完成了。
我认为这里不需要改进,因为假设您在$jmp = 1
或$min >= $max
行为不当的情况下不需要“防弹”行为。
答案 1 :(得分:1)
$e
循环中的for
增量器更多是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;
}
我认为如果你注意不重复使用变量(比如函数参数)并让它们更好地阅读名称,那么改进就是它自己的。