Numeric arrays

at 2005-05-29 in General by friebe (1 comments)

PHP's handling of arrays is superb: It's easy to create them. It's easy to manipulate them (there's about a gazillion functions over here). It's easy to access them. Their hashing algorithm is fast as a lightning. Aah: Hashing. Hashes and arrays are indistinguishable in PHP. And that's where the problem lies when communicating with languages where this is not the case. Hrm, you may think: $a= array(1, 2, 3); is numeric and $a= array("key" => "val"); is a hash, for sure. But how do we find out programmatically?

I stumbled upon a piece of sourcecode reading:

<?php 
if
(array_keys($a) === range(0, sizeof($a)- 1)) { // numeric
}
?>

"What's the problem - this looks like a very elegant solution?", you may think. Well, the problem is that for large arrays, it creates two new arrays of the same size as the passed array, one with the keys and one with range() and the compares them (which internally goes over each element of both lists and checks them for equality).

What I was interested in was finding out if there's a faster solution (except, of course, writing a builtin function). Therefore, I wrote a small script containing various methods of finding out whether an array is numeric. These are the different strategies:

#1: The code snippet from above
<?php 
class KeyRangeStrategy extends Object {

function execute($a) {
return is_array
($a) && (array_keys($a) === range(0, sizeof($a)- 1));
}
}
?>

#2: Use key() and next()
<?php 
class KeyNextStrategy extends Object {

function execute($a) {
if
(!is_array($a)) return FALSE;
$i= 0;
do
{
if
(key($a) !== $i++) return FALSE;
} while (FALSE !== next($a));
return TRUE;
}
}
?>

#3: Use a for() loop
<?php 
class ForLoopStrategy extends Object {

function execute($a) {
if
(!is_array($a)) return FALSE;
for
($k= array_keys($a), $s= sizeof($k), $i= 0; $i &lt; $s; $i++) {
if
($k[$i] !== $i) return FALSE;
}
return TRUE;
}
}
?>

#4: Use list() and each()
<?php 
class ListEachStrategy extends Object {

function execute($a) {
if
(!is_array($a)) return FALSE;
$i= 0;
while
(list($key, )= each($a)) {
if
($key !== $i++) return FALSE;
}
return TRUE;
}
}
?>

#5: Use foreach()
<?php 
class ForeachStrategy extends Object {

function execute($a) {
if
(!is_array($a)) return FALSE;
$i= 0;
foreach
(array_keys($a) as $k) {
if
($k !== $i++) return FALSE;
}
return TRUE;
}
}
?>

To test the strategies, I used the following test data:
  • A small array with numeric values
  • An array with 1000 elements
  • An array containing two strings
  • An array containing a wrong key
  • A hash

The script's sourcecode is available here, the results here.

And the winner is: foreach()! Although it does not perform as well on the small arrays, it is nearly twice as fast as the KeyRange strategy on the array created with range(1, 1000);. Also interesting is the fact that the for() loop is slower than foreach. This is due to the fact that the array access whithin the loop ($k[$i]) takes more time than simply reading a local variable.



Subscribe

You can subscribe to the XP framework's news by using RSS syndication.


Categories

News
General
PHP5
Announcements
RFCs
Further reading
Examples
Editorial
EASC
Experiments
Unittests
Databases

Related

Find related articles by a search for «Numeric».