生成具有不规则步长的范围。优化

发布于 2024-12-22 21:04:21 字数 1524 浏览 2 评论 0原文

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+
)

Does PHP have existing functionality for irregular step ranges, is there a common solution to provide this functionality, or how can the following function be optimized?

The first function is the function I am concerned about. The second function is a real world use case that generates an array to populate values for a function that outputs a select dropdown for 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 = '

The result of the previous:

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+
)
. $prev_step . ' -

The result of the previous:


 . ($price - 1);
        $price_arr[] = $price_str;
        $prev_step = $price;
    }
    $price_arr[] = '

The result of the previous:


 . end($price_steps) . "+";

    return $price_arr;
}

print_r(prices());

The result of the previous:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

新雨望断虹 2024-12-29 21:04:21

重复的加法最好用乘法来代替,重复的乘法最好用幂次来代替——你已经这么做了。

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

Repeated addition is best replaced by multiplication, and repeated multiplication is best replaced by raising to powers -- which you've done.

I see nothing here that requires improvement assuming you don't need "bulletproof" behavior in the face of $jmp = 1 or $min >= $max badly-behaved inputs.

旧伤慢歌 2024-12-29 21:04:21

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;
}

我认为如果你注意不要重复使用变量(如函数参数)并让它们更好地读取名称,改进就会自然而然地出现。

The $e incrementor in the for loop is more of a while(1) endless loop.

So instead misusing the incrementor in pow(), do the pow on your own by just multiplying once per iteration. Calling pow() can be pretty expensive, so doing the pow calculation your own would better distribute the multiplication onto each iteration.

Edit: The following is a variant of your function that distributes the pow() calculation over the iteration. Additionally it does more proper variable initialisation (the return value was not set for example), gives notice if $min and $max are swapped and corrects that, uses abs instead of your ternary, throws an exception if an invalid value was given for log(), renamed some variables and add $num to the return value as key first to spare the array_unique operation at the end:

/**
 * @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;
}

In case you feel experimental, it's also possible to turn the two loops (for+foreach) into one, but the readability of the code does not benefit from it:

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;
}

I think if you take care to not re-use variables (like the function parameter) and give them better to read names, improvement comes on it's own.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文