Reputation: 1048
I'm trying to find the highest key of a PHP array, based on another value.
$values = array(0,0,50,100,200,400,800);
If I let's say I have the value of 125, it should return 3. And it should return 5 if I have any value between 400 and 799.
$output = -1;
$input = 436;
$length = count($values);
for($i=1;$i<=$length;$i++){
if($values[$i]<=$input) { $output++; }
}
// Returns 5
I can loop through the array, but there is 100 values, and that can slow the page down a lot because it is used ~20 times per page load per user. Is there a special function I'm missing? Or am I going to have to foreach the array?
The array is always in order and never changes.
Upvotes: 1
Views: 304
Reputation: 154701
Sorry, but AFAIK you really have to loop this trough.
Iff the array is ordered, you could find the first index that is higher and then just add the remaining.
EDIT: Here is the code I used to benchmark:
set_time_limit(0);
$a = array(0,0,50,100,200,400,800);
$a = array_merge(range(0, 100000), $a);
sort(a); // we need this since array_merge will not maintain the sequence
$result = array
(
'testWithForeach' => 0,
'testWithArrayFlip' => 0,
'testWithArraySearch' => 0,
);
foreach (range(0, 1000, 10) as $n) // search values $n to try
{
for ($i = 0; $i < 10; ++$i) // how many times to run each test
{
foreach (array_keys($result) as $test) // divide the CPU usage fairly (inner-most loop)
{
$start = microtime(true); call_user_func($test, $a, $n); $result[$test] += (microtime(true) - $start);
}
}
}
asort($result);
echo '<pre>';
print_r($result);
echo '</pre>';
function testWithForeach($a, $n)
{
foreach ($a as $key => $value)
{
if ($value >= $n)
{
$result = $key; break;
}
}
return $result;
}
function testWithArrayFlip($a, $n)
{
$a[] = $n; sort($a); $a = array_flip($a); return ($a[$n] - 1);
}
function testWithArraySearch($a, $n)
{
$a[] = $n; sort($a); return (array_search($n, $a) - 1);
}
All the methods are run under similar conditions and spread over CPU time.
I tested all the $n
values from 0 to 1000, using 10 as step (100 in total).
Each $n
/ method combination was ran 10 times, and the results I got were:
Array
(
[testWithForeach] => 19.338931560516
[testWithArraySearch] => 96.209128856659
[testWithArrayFlip] => 133.85276961327
)
I tried to be as fair as possible, actual running times may vary depending on $n
and other conditions.
Upvotes: 1
Reputation: 46896
You may be able to do this using array_flip().
[ghoti@pc ~]$ php -r '$n=150; $a=array(0,0,50,100,200,400,800); $a[]=$n; sort($a); $f=array_flip($a); print $f[$n]-1 . "\n";'
3
[ghoti@pc ~]$ php -r '$n=401; $a=array(0,0,50,100,200,400,800); $a[]=$n; sort($a); $f=array_flip($a); print $f[$n]-1 . "\n";'
5
[ghoti@pc ~]$ php -r '$n=200; $a=array(0,0,50,100,200,400,800); $a[]=$n; sort($a); $f=array_flip($a); print $f[$n]-1 . "\n";'
4
[ghoti@pc ~]$ php -r '$n=0; $a=array(0,0,50,100,200,400,800); $a[]=$n; sort($a); $f=array_flip($a); print $f[$n]-1 . "\n";'
1
How does this work?
Let's break it down.
$n=0;
Our number.$a=array(0,0,50,100,200,400,800);
Our array.$a[]=$n;
We add our number to the array...sort($a);
Sort the thing to place our number in the correct position...$f=array_flip($a);
Then we exchange values with indices,print $f[$n]-1
And return the value (formerly the index) of the item before the one we added.There may be confusion if $a contains multiple entries of the same number, for example 0
in your example. If this happens, you may need to adjust your adjustment (-1
in my example) because an index can only appear once in an array. (For example, if 0
appeared three times, you'd need to adjust your result with -2
. This adjustment could be added with extra code, but I'm sure you can figure that part out yourself. :)
This avoids the loop, but be careful if $n=0
.
Upvotes: 1