I've got a big hashtable (array with string indexes) and lo开发者_如何学运维oking for a function that quickly picks the first (ideally, also Nth) element from it. array_shift()
and reset()
are too slow for my needs.
UPDATE: i'm also not looking for a reference-based solution, the function should accept expressions as in get_first(some_func_returning_array())
ANSWER array_slice method (kudos Gumbo) seems to be the winner. Complete benchmarking code
function bigary($n) {
$a = array();
$s = range('A', 'Z');
do {
shuffle($s);
$a[substr(implode('', $s), rand(10, 20))] = $n;
} while(--$n);
return $a;
}
function timeit($name, $fn) {
global $results;
$loops = 1000;
$size = 5432;
static $a;
if(!$a) $a = bigary($size);
$t = microtime(1);
for($i = 0; $i < $loops; $i++)
$b = $fn($a);
$results[$name] = microtime(1) - $t;
}
timeit('dummy', function ($a) {
// benchmark php function call overhead
});
timeit('array_shift', function ($a) {
return array_shift($a);
});
timeit('reset', function ($a) {
return reset($a);
});
timeit('foreach', function ($a) {
foreach($a as $b) return $b;
});
timeit('keys', function ($a) {
$b = array_keys($a);
return $a[$b[0]];
});
timeit('values', function ($a) {
$b = array_values($a);
return $b[0];
});
timeit('slice', function ($a) {
$b = array_slice($a, 0, 1);
return reset($b);
});
asort($results);
foreach($results as $name => $time)
printf("%20s = %.3f\n", $name, $time);
Results:
dummy = 0.393
slice = 0.433
values = 0.824
foreach = 0.929
reset = 0.935
array_shift = 0.954
keys = 1.371
Use array_slice
to get an array of just the n-th item and array_pop
to finally get it:
$nthItem = array_pop(array_slice($arr, $n, 1));
Your benchmark may be flawed, since:
$fn = function ($a) {
return array_shift($a);
};
timeit('array_shift', $fn);
array_shift = 1.242 (5432)
and
timeit('array_shift', array_shift);
array_shift = 0.026 (4433)
but also
$fn = function ($a) { }
timeit('empty lambda', $fn);
empty lambda = 0.501 (0)
That being said, another possible solution:
$v = array_values($a);
return $v[ $index ];
Sample Code:
$t = microtime(1);
$v = array_values($a); // cached
while($loops--) {
$b = $v[$loops];
}
array_values = 0.002 (5432)
I don't think you can get any faster than reset()
/end()
for first/last element.
As for N'th element, I can't think of anything better than this:
function (&$hashmap, $n) {
$keys = array_keys($hashmap);
return $hashmap[$keys[$n]];
}
Of course for performance this can tuned to have a pre-cached $keys
array (if hashmap doesn't change very often). In that case maybe even 0'th element retrieval may be faster than with reset()
To get the first:
function array_first(array $array) {
foreach ($array as $value) return $value;
return false;
}
And although I haven't tested this for speed, you could try using array_values()
to convert the array to a numerically indexed array.
To get the first element try to reset the array's pointer with reset ( array &$array ). Then get the current value with current(). To get the Nth element use the end(), to set the pointer to the last item. At this point you should be able to get the Nth item with current().
精彩评论