Creating a range with irregular steps. optimized

Does PHP have existing functionality for irregular ranges of steps, is there a general solution for providing this function, or how to optimize the next function?

The first function is the function I'm worried about. The second function is a real use case that generates an array to populate values ​​for a function that displays a drop down menu 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 = '$' . $prev_step . ' - $' . ($price - 1); $price_arr[] = $price_str; $prev_step = $price; } $price_arr[] = '$' . end($price_steps) . "+"; return $price_arr; } print_r(prices()); 

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+ ) 
+4
source share
2 answers

The increment $e in a for loop is more of an infinite while(1) .

So instead of using the increment in pow() incorrectly, do pow yourself, just multiplying iteration once. Calling pow() can be quite expensive, so calculating your own pow better distributes the multiplication over each iteration.

Edit: Below is a variant of your function that distributes the calculation of pow() by iteration. In addition, it makes the initialization of variables more correct (for example, the return value has not been set), reports that if $min and $max are reversed and corrects this, instead of abs instead of ternary, an exception is thrown if an invalid value was specified for log() , renamed to some variables and added $num to the return value as a key to first save 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 is also possible to turn two loops ( for + foreach ) into one, but the readability of the code does not bring him any benefit:

 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 that if you take care not to reuse the variables (for example, the function parameter) and give them better read names, the improvement comes to it yourself.

+1
source

Repeated additions are best replaced by multiplication, and repeated multiplication is best replaced by promotion — what you did.

I don’t see anything here that needs to be improved, assuming that you don’t need a “bulletproof” behavior in case of incorrect entries $jmp = 1 or $min >= $max .

+2
source

Source: https://habr.com/ru/post/1387851/


All Articles