PHP treats all arrays as associative, so there aren't any built in functions. Can anyone recommend a fairly efficient way to check if an array contains only numeric keys?
Basically, I want to be able to differentiate between this:
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
and this:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
Here's the method I use:
Note that this doesn't account for special cases like:
Sorry, can't help you with that. It's also somewhat performant for decently sized arrays, as it doesn't make needless copies. It is these little things that makes Python and Ruby so much nicer to write in... :P
As stated by the OP:
it is not quite sensible (IMHO) to write a function that checks if an array is associative. So first thing first: what is a key in a PHP array?:
That means there are 3 possible cases:
We can check each case with the following functions.
Case 1: all keys are numeric / integers.
Note: This function returns true for empty arrays too.
Case 2: all keys are strings.
Note: This function returns true for empty arrays too.
Case 3. some keys are strings, some keys are numeric / integers.
Note: This function returns true for empty arrays too.
It follows that:
(which is by definition, as in "the empty set is a subset of any set A because all its elements belong to A").
Now, for an array to be a "genuine" array that we are all accustomed to, meaning:
We can check with the following function.
Case 3a. keys are numeric / integers, sequential, and zero-based.
Note: This function returns true for empty arrays too.
Caveats / Pitfalls (or, even more peculiar facts about array keys in PHP)
Integer keys
The keys for these arrays are integers:
String keys
The keys for these arrays are strings:
Integer keys that look like strings
If you think the key in
array("13" => "b")
is a string, you are wrong. From the doc here:For example, the key for these arrays are integers:
But the key for these arrays are strings:
What's more, according to the doc,
So the key for this array may or may not be an integer - it depends on your platform.
Even worse, PHP tends to be buggy if the integer is near the 231 = 2,147,483,648 boundary (see bug 51430, bug 52899). For example, on my local environment (PHP 5.3.8 on XAMPP 1.7.7 on Windows 7),
var_dump(array("2147483647" => "b"))
givesbut on this live demo on codepad (PHP 5.2.5), the same expression gives
So the key is an integer in one environment but a string in another, even though
2147483647
is a valid signed 32-bit integer.I've used both
array_keys($obj) !== range(0, count($obj) - 1)
andarray_values($arr) !== $arr
(which are duals of each other, although the second is cheaper than the first) but both fail for very large arrays.This is because
array_keys
andarray_values
are both very costly operations (since they build a whole new array of size roughly that of the original).The following function is more robust than the methods provided above:
Also note that if you don't care to differentiate sparse arrays from associative arrays you can simply return
'assoc'
from bothif
blocks.Finally, while this might seem much less "elegant" than a lot of "solutions" on this page, in practice it is vastly more efficient. Almost any associative array will be detected instantly. Only indexed arrays will get checked exhaustively, and the methods outlined above not only check indexed arrays exhaustively, they duplicate them.
I know it's a bit pointless adding an answer to this huge queue, but here's a readable O(n) solution that doesn't require duplicating any values:
Rather than check the keys to see if they are all numeric, you iterate over the keys that would be there for a numeric array and make sure they exist.
One more fast from source. Fit encoding of
json_encode
(andbson_encode
). So has javascript Array compliance.After some local benchmarking, debugging, compiler probing, profiling, and abusing 3v4l.org to benchmark across more versions (yes, I got a warning to stop) and comparing against every variation I could find...
I give you an organically derived best-average-worst-case scenario associative array test function that is at worst roughly as good as or better than all other average-case scenarios.
From https://3v4l.org/rkieX: