How to check if PHP array is associative or sequential?
Asked Answered
H

60

925

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 "is a list" (contains only numeric keys starting from 0)?

Basically, I want to be able to differentiate between this:

$sequentialArray = [
    'apple', 'orange', 'tomato', 'carrot'
];

and this:

$assocArray = [
    'fruit1' => 'apple',
    'fruit2' => 'orange',
    'veg1' => 'tomato',
    'veg2' => 'carrot'
];
Haematinic answered 6/10, 2008 at 7:1 Comment(4)
This method has caveats, but often I just do if (isset($array[0])), which is simple and fast. Of course, you should first be sure the array isn't empty, and you should have some knowledge on the possible contents of the array so that the method couldn't fail (like mixed numeric/associative, or non-sequential).Tyrus
@OlleHärstedt Not according to US High Court. ;-)Esmaria
@MCEmperor Wiki's own page about "tomato" states it's a fruit en.wikipedia.org/wiki/Tomato definitions change drastically when money comes into play :P Just ask Jaffa "cake" about itAraucanian
PHP 8.1 introduces a new function for it: array_is_list: https://mcmap.net/q/53406/-how-to-check-if-php-array-is-associative-or-sequentialBrunner
D
793

Since 8.1 PHP has a simple answer, array_is_list().

For the legacy code you can use the following function (wrapping it in function_exists() to make it portable):

if (!function_exists('array_is_list')) {
    function array_is_list(array $arr)
    {
        if ($arr === []) {
            return true;
        }
        return array_keys($arr) === range(0, count($arr) - 1);
    }
}

And then you can use the this function with any PHP version.

var_dump(array_is_list([])); // true
var_dump(array_is_list(['a', 'b', 'c'])); // true
var_dump(array_is_list(["0" => 'a', "1" => 'b', "2" => 'c'])); // true
var_dump(array_is_list(["1" => 'a', "0" => 'b', "2" => 'c'])); // false
var_dump(array_is_list(["a" => 'a', "b" => 'b', "c" => 'c'])); // false
Drugge answered 6/10, 2008 at 7:1 Comment(15)
Very elegant solution. Note that it returns TRUE in the (ambiguous) case of an empty array.Crespo
I think it is more useful to think of sequential arrays as a special case of associative arrays. So every array is associative, but only some are sequential. Therefore, a function isSequential() would make more sense than isAssoc(). In such a function, the empty array should be seen as sequential. The formula could be array() === $arr || !isAssoc($arr).Vaporimeter
I think this would avoid a lot of potential cpu time and memory if one would check if isset($arr[0]) is false before extracting all the keys as is it clearly associative if the array is not empty but has no element in 0 position. As "most" real associative arrays have strings as keys this should be a nice optimisation for the general case of such function.Esmeraldaesmerelda
@Esmeraldaesmerelda - Your optimization should use array_key_exists instead of isset because if the zero element is a null value, the isset will return false incorrectly. A null value should ordinarily be a legitimate value in such an array.Nial
@MAChitgarha, your edit changed the behaviour of the function without any explanation of why, and made it contradict the description in the prose above of what it's actually supposed to do. I've reverted it.Drugge
why is the second case yield to false? because of "0" key?Catena
Not sure if this still works with negative array keys: wiki.php.net/rfc/negative_array_indexStrop
This answer uses O(n) space. A good solution should use O(1) IMHO.Castlereagh
Since PHP 8.1.0 there is array_is_list(): Determines if the given array is a list. An array is considered a list if its keys consist of consecutive numbers from 0 to count($array)-1. This is contrary to if (array() === $arr) return false; but it considers an empty array is a sequence with exactly 0 elements.Maunder
I found this answer as great! I think we can set the return type of the function with the code function array_is_list(array $array): bool { }. It will be more elegant.Clearheaded
I think the function with the following way and the use of this one-line code in the function will reduce some code { return $a === [] || (array_keys($a) === range(0, count($a) - 1)); }Clearheaded
IIRC return !$a || ($k = array_keys($a) && $k === array_flip($k)); , see as well the comments on php.net/array_is_list . And bust any performance/memory myths by running your own metrics against the PHP versions you have/want to support. Symfony Polyfills aren't portable, they crash after dependency resolution of composer when executing with different PHP versions, their backwards compat is also very limited. Just my 2 cents.Romeo
@Esmeraldaesmerelda Or iterate it in a foreach loop, set up an independent iterator and increment it at the end of the loop and just check if the key equals the iterator, return false immediately if it does.Kyrakyriako
In user contributed notes on PHP website said Polyfills that call array_keys(), array_values() or range() are inefficient because they create new arrays unnecessarily. I have no idea how to test but Is it different? ..in performance.Harshman
Test result compare with PHP original one, this polyfill, and code from user contributed note on PHP. 3v4l.org/paaK1Harshman
R
489

To merely check whether the array has non-integer keys (not whether the array is sequentially-indexed or zero-indexed):

function has_string_keys(array $array) {
  return count(array_filter(array_keys($array), 'is_string')) > 0;
}

If there is at least one string key, $array will be regarded as an associative array.

Rivero answered 6/10, 2008 at 7:1 Comment(11)
This method is much better than it seems. If count(filtered_array) == count(original_array), then it is an assoc array. If count(filtered_array) == 0, then it is an indexed array. If count(filtered_array) < count(original_array), then the array has both numeric and string keys.Fossilize
Way to slow. This will iterate and apply a function. Look below for faster alternatives or simply check the first key for being int.Cervelat
This returns false for ["1" => "foo", 2, 3]. Is there really no way to check if a key was originally defined as a string? PHP seems to cast everything to an int in an array definition if it can. Brutal.Parchment
@MikePretzlaw of course it iterates; there is (obviously) no possible way to determine whether all the keys of the array are ints without looking at all the keys in the array. I assume the non-iterating alternatives we're supposed to be seeing below are ones like $isIndexed = array_values($arr) === $arr;? To which I ask: how do you think array_values() works? How do you think === applied to arrays works? The answer is of course that they also iterate over the array.Drugge
@Parchment "PHP seems to cast everything to an int in an array definition if it can." - yep, that's exactly what happens. The biggest WTF is that it even does this to floats; if you try var_dump([1.2 => 'foo', 1.5 => 'bar']); you'll discover that you get the array [1 => 'bar']. There's no way whatsoever to find out a key's original type. Yes, all this is awful; PHP's arrays are by far the worst part of the language, and most of the damage is irreparable and owes to the idea of using a single construct for traditional arrays and traditional hashmaps being an awful one from the beginning.Drugge
@MarkAmery The above, while simple, guarantees a 100% walk of the array. It would be more efficient, especially if you're dealing with large arrays, if you were checking for string or int and broke out on the first you found. For instance: function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }Grani
@Grani Your code work very fast but it cannot detect sequential array. Example array(1 => 'a', 0 => 'b', 2 => 'c') will become false (sequential array) while it should be true (associative array). toolsqa.com/data-structures/array-in-programming I'm not sure is the key must be ascending order? (0, 1, ...)Harshman
@Harshman - indeed, the very first line of the answer says that this answer does not determine whether the array has sequential indexes. To do so, see Mark Amery's answer that uses array_keys.Communion
@Communion I was mentioned to Thought's comment not to the answer (by Captain kurO). It is different.Harshman
@Grani 's answer is flawed because it returns true as soon as it encounters a string key. I think this is a better algo: function is_associative(array $array): bool { foreach ($array as $key => $value) { if (!is_string($key)) return false; } return true; } Adding my own answer if I can.Gaudery
@godzillante, That's what it should do. Your suggestion returns true only if all the keys are strings. We want it to return true whenever at least one of the keys is a string (and possibly also if they are not sequential integers).Stonedead
L
148

Surely this is a better alternative.

<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;
Lathrop answered 6/10, 2008 at 7:1 Comment(9)
This will duplicate the values in the array, which is potentially very expensive. You're much better off examining the array keys.Dexamethasone
If one of the array values is unset, this code no longer returns a valid result (e.g., unset($arr[0]); $isIndexed = array_values($arr) === $arr; // returns false.)Upmost
Please look at my answer below which while not a pithy one liner actually works for large arrays.Unsavory
-1. Try: $a=array(1=>"foo"); var_dump(array_values($a)===$a); or even: $a=array(1,2,3,4); unset($a[2]); var_dump(array_values($a)===$a);Hurst
I just used ==; I don't think there is a need for === here. But to answer the "unset and it doesn't work": once you unset the first element, it's no longer an integer-indexed array starting at 0. So IMO it does work.Coy
Agree with @grantwparks: A sparse array isn't indexed. Interestingly because there's no way to actually delete an element out of the middle of an indexed array PHP is basically declaring all arrays as associative and numeric is just a 'make up the key for me' version.Arrack
The only problem I have with this is that the === will waste time checking if the values are equal, even though we are only interested in the keys. For this reason I prefer the $k = array_keys( $arr ); return $k === array_keys( $k ); version.Gastronomy
An added note, this fails on arrays specified with numeric keys that are out of order. e.g. $myArr = array ( 0 => 'a', 3 => 'b', 4 => 1, 2 => 2, 1 => '3' ); One potential work around is running ksort($arr) before doing the testJere
I think that this is the best one !Maite
W
79

Many commenters in this question don't understand how arrays work in PHP. From the array documentation:

A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. "8" will be interpreted as 8, while "08" will be interpreted as "08"). Floats in key are truncated to integer. The indexed and associative array types are the same type in PHP, which can both contain integer and string indices.

In other words, there is no such thing as an array key of "8" because it will always be (silently) converted to the integer 8. So trying to differentiate between integers and numeric strings is unnecessary.

If you want the most efficient way to check an array for non-integer keys without making a copy of part of the array (like array_keys() does) or all of it (like foreach does):

function keyedNext( &$arr, &$k){
    $k = key($arr);
    return next($arr);
}

for ($k = key(reset($my_array)); is_int($k); keyedNext($my_array,$k))
    $onlyIntKeys = is_null($k);

This works because key() returns NULL when the current array position is invalid and NULL can never be a valid key (if you try to use NULL as an array key it gets silently converted to "").

Wandie answered 6/10, 2008 at 7:1 Comment(7)
This doesn't work for non-sequential integer keys. Try it with [2 => 'a', 4 => 'b'].Pyrophyllite
@DavidJ, What do you mean by "doesn't work"? It successfully determines that all the keys are integers. Are you claiming that an array like the one you posted shouldn't be considered a "numeric array"?Lizbeth
A non-associative array must have keys ranging from 0 to count($array)-1, in this strict order. A preliminary check with is_array() may help. Add an increasing variable to check the key sequence: for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k; That settles the deal.Coraliecoraline
Using foreach instead of explicit iteration is about twice faster.Coraliecoraline
If you want to make this into a function: function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }Landside
Numeric arrays do not necessarily need to have keys from 0 to count($arr)-1. These two examples are perfect non-associative arrays with non sequential keys: $arr = [ 'A', 'B', 'C', 'D' ]; unset( $arr[2] ); or $arr = [ 2 => 'A', 4 => 'B', 9 => 'C', 'D' ];Misbehave
My favourite answer on here. Duplicating all the keys can get expensive, and it's a big memory cost that could be nearly double the total memory taken by the dataset.Yolanda
D
53

PHP 8.1 adds a built-in function to determine whether an array is a list with those semantics, or not. the function is array_is_list:

$list = ["a", "b", "c"];

array_is_list($list); // true

$notAList = [1 => "a", 2 => "b", 3 => "c"];

array_is_list($notAList); // false

$alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];

array_is_list($alsoNotAList); // false

Please note that this function returns true on empty arrays.

array_is_list([]); // true

reference

Demonism answered 6/10, 2008 at 7:1 Comment(7)
Thanks for pointing out the native solution! You might add that there also is a polyfill in packagist.org/packages/symfony/polyfill-php81 so this should be resolved once and for all for anyone using PHP 7.1 and above. Just use symfony/polyfill-php81 provided by composer.Brno
It's a shame that this answer will never get to the top.Allotropy
Have faith. Stack Overflow will soon roll out their Trending sort algorithm and it will have an easier time getting noticed.Youlandayoulton
I made an array_is_assoc function that first checks if array is empty (which returns True) and otherwise returns ! array_is_list()Asel
@MarcelHernandez Agreed. SO needs an algorithm that notices new answers that get upvotes, to account for changes in a language.Asel
Yes, this answer is correct The answer you have added in this post only works for php 8.1 and above and if anyone wants to use an older version, they should use this link answer .Towne
This solution is great! This function array_is_list returns true if the given array is a list, otherwise false. Apart of that, the given array is considered as a list if its keys consist of consecutive numbers from 0 to count($array)-1.Clearheaded
C
42

As stated by the OP:

PHP treats all arrays as associative

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?:

The key can either be an integer or a string.

That means there are 3 possible cases:

  • Case 1. all keys are numeric / integers.
  • Case 2. all keys are strings.
  • Case 3. some keys are strings, some keys are numeric / integers.

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.

//! Check whether the input is an array whose keys are all integers.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array whose keys are all integers.
*/
function IsArrayAllKeyInt($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return array_unique(array_map("is_int", array_keys($InputArray))) === array(true);
}

Case 2: all keys are strings.

Note: This function returns true for empty arrays too.

//! Check whether the input is an array whose keys are all strings.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array whose keys are all strings.
*/
function IsArrayAllKeyString($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return array_unique(array_map("is_string", array_keys($InputArray))) === array(true);
}

Case 3. some keys are strings, some keys are numeric / integers.

Note: This function returns true for empty arrays too.

//! Check whether the input is an array with at least one key being an integer and at least one key being a string.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array with at least one key being an integer and at least one key being a string.
*/
function IsArraySomeKeyIntAndSomeKeyString($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return count(array_unique(array_map("is_string", array_keys($InputArray)))) >= 2;
}

It follows that:


Now, for an array to be a "genuine" array that we are all accustomed to, meaning:

  • Its keys are all numeric / integers.
  • Its keys are sequential (i.e. increasing by step 1).
  • Its keys start from zero.

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.

//! Check whether the input is an array whose keys are numeric, sequential, and zero-based.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array whose keys are numeric, sequential, and zero-based.
*/
function IsArrayKeyNumericSequentialZeroBased($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return array_keys($InputArray) === range(0, count($InputArray) - 1);
}

Caveats / Pitfalls (or, even more peculiar facts about array keys in PHP)

Integer keys

The keys for these arrays are integers:

array(0 => "b");
array(13 => "b");
array(-13 => "b");          // Negative integers are also integers.
array(0x1A => "b");         // Hexadecimal notation.

String keys

The keys for these arrays are strings:

array("fish and chips" => "b");
array("" => "b");                                   // An empty string is also a string.
array("[email protected]" => "b");    // Strings may contain non-alphanumeric characters.
array("stack\t\"over\"\r\nflow's cool" => "b");     // Strings may contain special characters.
array('$tα€k↔øv∈rflöw⛄' => "b");                    // Strings may contain all kinds of symbols.
array("functіon" => "b");                           // You think this looks fine? Think again! (see https://mcmap.net/q/54622/-how-do-i-fix-this-missing-semicolon-syntax-error-in-javascript/1402846)
array("ま말轉转ДŁ" => "b");                         // How about Japanese/Korean/Chinese/Russian/Polish?
array("fi\x0sh" => "b");                            // Strings may contain null characters.
array(file_get_contents("https://www.google.com/images/nav_logo114.png") => "b");   // Strings may even be binary!

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:

Strings containing valid integers will be cast to the integer type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer.

For example, the key for these arrays are integers:

array("13" => "b");
array("-13" => "b");                        // Negative, ok.

But the key for these arrays are strings:

array("13." => "b");
array("+13" => "b");                        // Positive, not ok.
array("-013" => "b");
array("0x1A" => "b");                       // Not converted to integers even though it's a valid hexadecimal number.
array("013" => "b");                        // Not converted to integers even though it's a valid octal number.
array("18446744073709551616" => "b");       // Not converted to integers as it can't fit into a 64-bit integer.

What's more, according to the doc,

The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). 64-bit platforms usually have a maximum value of about 9E18, except for Windows, which is always 32 bit. PHP does not support unsigned integers.

So the key for this array may or may not be an integer - it depends on your platform.

array("60000000000" => "b");                // Array key could be integer or string, it can fit into a 64-bit (but not 32-bit) integer.

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")) gives

array(1) {
    [2147483647]=>
    string(1) "b"
}   

but on this live demo on codepad (PHP 5.2.5), the same expression gives

array(1) {
    ["2147483647"]=>
    string(1) "b"
}

So the key is an integer in one environment but a string in another, even though 2147483647 is a valid signed 32-bit integer.

Cleft answered 6/10, 2008 at 7:1 Comment(2)
Except, as I mention below, it involves creating a duplicate array to the one being checked, making it very expensive for large arrays, and a potential source of out of memory crashes on shared hosts.Unsavory
I am suprised you can cast "-13" to a string, but not "+13". I guess nobody would write "+13" instead of "13", but it is still somewhat weiredCurd
L
37

Speed-wise:

function isAssoc($array)
{
    return ($array !== array_values($array));
}

Memory-wise:

function isAssoc($array)
{
    $array = array_keys($array); return ($array !== array_keys($array));
}
Lobotomy answered 6/10, 2008 at 7:1 Comment(1)
the following array: array(02=>11,1,2,456); is shown as not having numerical keys using the above algorithm, even if 02===2Bob
E
31

Actually the most efficient way is thus:

function is_assoc($array){
   $keys = array_keys($array);
   return $keys !== array_keys($keys);
}

This works because it compares the keys (which for a sequential array are always 0,1,2 etc) to the keys of the keys (which will always be 0,1,2 etc).

Laravel use this approach.

Elfriedeelfstan answered 6/10, 2008 at 7:1 Comment(2)
Clever, but not good. Why is this "most efficient"? It would be a lot more readable to just compare the array_keys($a) to range(0, count($a)). The most clever solution is rarely the best one in my experience. Especially when being clever adds literally no value over the obvious and clean alternative.Universalism
It's not efficient insofar as it involves calling array_keys vs. just checking until you find a non-sequential integer index. Under the hood you're doing that anyway, but you already duplicated a big array.Unsavory
K
23
function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}
Kanter answered 6/10, 2008 at 7:1 Comment(5)
This is the only answer (at the time of my comment) that can deal with the following: $array = array(0=>'blah', 2=>'yep', 3=>'wahey')Harms
but array('1'=>'asdf', '2'=>'too') will be regarded as associative array while it's actually not (the keys are actually string)Rivero
@CaptainkurO You mean numerical. It is an associative array.Marta
This function returns true if the keys are: zero, integers (positive only), an empty string, or any combination of the above, such as the string "09". This function does not take the order of the keys into account. So array(0=>'blah', 2=>'yep', 3=>'wahey'), array(0=>'blah', 2=>'yep', 1=>'wahey') and array('blah', 'yep', 'wahey') are all associative according to this function, while array('a'=>'blah', 'b'=>'yep', 'c'=>'wahey') is not.Cleft
@CaptainkurO you are incorrect. '1' and '2' will be stored as integers. Read the quoted part of squirrel's answer from May 11, 2011 at 19:34. PHP does not store string keys that look exactly like integers. It converts those to integers.Rusty
U
18

I've used both array_keys($obj) !== range(0, count($obj) - 1) and array_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 and array_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:

function array_type( $obj ){
    $last_key = -1;
    $type = 'index';
    foreach( $obj as $key => $val ){
        if( !is_int( $key ) || $key < 0 ){
            return 'assoc';
        }
        if( $key !== $last_key + 1 ){
            $type = 'sparse';
        }
        $last_key = $key;
    }
    return $type;
}

Also note that if you don't care to differentiate sparse arrays from associative arrays you can simply return 'assoc' from both if 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.

Unsavory answered 6/10, 2008 at 7:1 Comment(0)
H
16

Here is another simple but powerful logic ( which is also used by great Laravel framework in it's internal mechanism )

/**
 * Determines if an array is associative.
 * @param  array  $array
 * @return bool
 */
function isAssoc(array $array)
{
    $keys = array_keys($array);

    return array_keys($keys) !== $keys;
}
Haematinic answered 6/10, 2008 at 7:1 Comment(1)
Thanks! I use Laravel, so I can just use the native Arr::isAssocBarra
I
14

I think the following two functions are the best way to go for checking 'if an array is associative or numeric'. Since 'numeric' could mean only numeric keys or only sequential numeric keys, two functions are listed below that check either condition:

function is_indexed_array(&$arr) {
  for (reset($arr); is_int(key($arr)); next($arr));
  return is_null(key($arr));
}

function is_sequential_array(&$arr, $base = 0) {
  for (reset($arr), $base = (int) $base; key($arr) === $base++; next($arr));
  return is_null(key($arr));
}

The first function checks if each key is an integer value. The second function checks if each key is an integer value and in addition checks if all keys are sequential starting at $base, which defaults to 0 and thus can be omitted if you do not need to specify another base value. key($my_array) returns null if the read pointer is moved past the end of the array, which is what ends the for loop and makes the statement after the for loop return true if all keys were integer. If not, the loop ends prematurely because a key is of type string, and the statement after the for loop will return false. The latter function in addition adds one to $base after each compare, to be able to check if the next key is of the correct value. The strict compare makes it also check if the key is of type integer. The $base = (int) $base part in the first section of the for loop can be left out when $base is omitted or if you make sure it is only called using an integer. But since I can't be sure for everybody, I left it in. The statement is executed only once, anyway. I think these are the most efficient solutions:

  • Memory wise: No copying of data or key ranges. Doing an array_values or array_keys may seem shorter (less code) but keep in mind what goes on in the background once you make that call. Yes there are more (visible) statements than in some other solutions, but that is not what counts, is it?
  • Time wise: Besides the fact that copying/extracting data and/or keys also takes time, this solution is more efficient than doing a foreach. Again a foreach may seem more efficient to some because it is shorter in notation, but in the background foreach also calls reset, key and next to do it's looping. But in addition it also calls valid to check the end condition, which is avoided here due to the combination with the integer check.

Remember that an array key can only be an integer or a string, and a strictly numeric string such as "1" (but not "01") will be translated into an integer. Which is what makes checking for an integer key the only needed operation besides counting if you want the array to be sequential. Naturally, if is_indexed_array returns false the array can be seen as associative. I say 'seen', because in fact they all are.

Idiotic answered 6/10, 2008 at 7:1 Comment(2)
This is the best answer. The definition of "associative" or "numeric" array depends on the specific situation.Pedro
If foreach is less efficient than the method used here then, aside from the inconvenience of using two different functions, the performance of this solution is better than mine (the preceding). I suspect it isn't, since foreach is recommended as the fastest way to go through an array.Unsavory
A
9

One way to approach this is to piggyback on json_encode, which already has its own internal method of differentiating between an associative array and an indexed array in order to output the correct JSON.

You can do this by checking to see if the first character returned after encoding is a { (associative array) or a [ (indexed array).

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}
Apologize answered 6/10, 2008 at 7:1 Comment(2)
The ksort() is not necessary in my opinion. This solution is working but it has to test if $arr is null and if json_encode fails, so a try/catch. + it is not really optimal if $arr is big.Canner
seems expensiveMenis
G
8
function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}

Fast, concise, and memory efficient. No expensive comparisons, function calls or array copying.

Gastronomy answered 6/10, 2008 at 7:1 Comment(1)
No function call, copying or expensive comparison, seems very efficient indeed.Hooker
S
7

There are many answers already, but here is the method that Laravel relies on within its Arr class:

/**
 * Determines if an array is associative.
 *
 * An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
 *
 * @param  array  $array
 * @return bool
 */
public static function isAssoc(array $array)
{
    $keys = array_keys($array);

    return array_keys($keys) !== $keys;
}

Source: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php

Slippy answered 6/10, 2008 at 7:1 Comment(3)
@Casey array_keys($keys) will return a sequential array of numbers (0...X) which has the same length of the original array. For example array_keys(["a", "b", "c"]) = [0, 1, 2]; array_keys([0, 1, 2]) = [0, 1, 2] (it's a sequential array because [0, 1, 2] !== [0, 1, 2]). Another example: array_keys(["a" => 5, "b" => 7, "c" => 10]) = ["a", "b", "c"]; array_keys(["a", "b", "c"]) = [0, 1, 2] (it's an associative array because ["a", "b", "c"] !== [0, 1, 2]). Hope it's clear (hard to explain extensively in a comment, at least for me)Narcoma
This algorithm is crazy, easy, understandable.Shanel
This will not work if you have a sequential array of associative rows.Canner
O
7

This function can handle:

  • array with holes in index (e.g. 1,2,4,5,8,10)
  • array with "0x" keys: e.g. key '08' is associative while key '8' is sequential.

the idea is simple: if one of the keys is NOT an integer, it is associative array, otherwise it's sequential.

function is_asso($a){
    foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
    return FALSE;
}
Overrule answered 6/10, 2008 at 7:1 Comment(2)
"if one of the keys is NOT an integer, it is associative array, otherwise it's sequential" - huh? No, this is simply wrong. There's room for argument over what constitutes an "associative" array, but the meaning of "sequential" is pretty unambiguous, and it's not the same as all keys being numbers.Drugge
If one of the keys is NOT an integer it IS associative by nature, however, it is only sequential if the keys go from 0 - length (array) - 1. It is NUMERIC however, if all the keys are only numbered, but may or may not work with many array functions that require a sequential array. If you convert the numeric array with holes into sequential by running array_values( array ) on it, then it would be converted to sequential.Remarque
C
6

Most answers have sub-optimal time/space complexity or are changing semantics. So, here is another answer with the fastest and most functionally correct solution:

function is_sequential_array(Array &$a) {
    $n = count($a);
    for($i=0; $i<$n; $i++) {
        if(!array_key_exists($i, $a)) {
            return false;
        }
    }
    return true;
}

This answer has following advantages over other answers:

  1. Space complexity of O(1) (many answers here use O(n) space!)
  2. Does not apply equality on keys (which is an unwanted and expensive operation)
  3. Treats input array as immutable (many answers have implicitly created a copy by applying mutating functions)
  4. Uses function array_key_exists instead of isset (remember, isset additionally checks for 'is not null', thereby changing semantics)
  5. Worst-case time complexity is O(n) (many answers here have best-case time complexity of O(n))
Castlereagh answered 6/10, 2008 at 7:1 Comment(0)
C
6

I noticed two popular approaches for this question: one using array_values() and other using key(). To find out which is faster, I wrote a small program:

$arrays = Array(
  'Array #1' => Array(1, 2, 3, 54, 23, 212, 123, 1, 1),
  'Array #2' => Array("Stack", 1.5, 20, Array(3.4)),
  'Array #3' => Array(1 => 4, 2 => 2),
  'Array #4' => Array(3.0, "2", 3000, "Stack", 5 => "4"),
  'Array #5' => Array("3" => 4, "2" => 2),
  'Array #6' => Array("0" => "One", 1.0 => "Two", 2 => "Three"),
  'Array #7' => Array(3 => "asdf", 4 => "asdf"),
  'Array #8' => Array("apple" => 1, "orange" => 2),
);

function is_indexed_array_1(Array &$arr) {
  return $arr === array_values($arr);
}

function is_indexed_array_2(Array &$arr) {
  for (reset($arr), $i = 0; key($arr) === $i++; next($arr))
    ;
  return is_null(key($arr));
}

// Method #1
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
  foreach ($arrays as $array) {
    $dummy = is_indexed_array_1($array);
  }
}
$end = microtime(true);
echo "Time taken with method #1 = ".round(($end-$start)*1000.0,3)."ms\n";

// Method #2
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
  foreach ($arrays as $array) {
    $dummy = is_indexed_array_2($array);
  }
}
$end = microtime(true);
echo "Time taken with method #1 = ".round(($end-$start)*1000.0,3)."ms\n";

Output for the program on PHP 5.2 on CentOS is as follows:

Time taken with method #1 = 10.745ms
Time taken with method #2 = 18.239ms

Output on PHP 5.3 yielded similar results. Obviously using array_values() is much faster.

Castlereagh answered 6/10, 2008 at 7:1 Comment(1)
bad benchmark. You didn't test for big arrays. On my computer starting at 10K+ elements method #2 is faster. Try with $arrays = Array( 'Array #1' => range(0, 50000), );Madalynmadam
H
4

For those using Laravel:

Arr::isAssoc returns true if the given array is an associative array. An array is considered "associative" if it doesn't have sequential numerical keys beginning with zero:

use Illuminate\Support\Arr;

$isAssoc = Arr::isAssoc(['product' => ['name' => 'Desk', 'price' => 100]]);

// true

$isAssoc = Arr::isAssoc([1, 2, 3]);

// false

https://laravel.com/docs/8.x/helpers#method-array-isassoc

Hooker answered 6/10, 2008 at 7:1 Comment(0)
P
4

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.

/**
 * Tests if an array is an associative array.
 *
 * @param array $array An array to test.
 * @return boolean True if the array is associative, otherwise false.
 */
function is_assoc(array &$arr) {
    // don't try to check non-arrays or empty arrays
    if (FALSE === is_array($arr) || 0 === ($l = count($arr))) {
        return false;
    }

    // shortcut by guessing at the beginning
    reset($arr);
    if (key($arr) !== 0) {
        return true;
    }

    // shortcut by guessing at the end
    end($arr);
    if (key($arr) !== $l-1) {
        return true;
    }

    // rely on php to optimize test by reference or fast compare
    return array_values($arr) !== $arr;
}

From https://3v4l.org/rkieX:

<?php

// array_values
function method_1(Array &$arr) {
    return $arr === array_values($arr);
}

// method_2 was DQ; did not actually work

// array_keys
function method_3(Array &$arr) {
    return array_keys($arr) === range(0, count($arr) - 1);
}

// foreach
function method_4(Array &$arr) {
    $idx = 0;
    foreach( $arr as $key => $val ){
        if( $key !== $idx )
            return FALSE;
        ++$idx;
    }
    return TRUE;
}

// guessing
function method_5(Array &$arr) {
    global $METHOD_5_KEY;
    $i = 0;
    $l = count($arr)-1;

    end($arr);
    if ( key($arr) !== $l )
        return FALSE;

    reset($arr);
    do {
        if ( $i !== key($arr) )
            return FALSE;
        ++$i;
        next($arr);
    } while ($i < $l);
    return TRUE;
}

// naieve
function method_6(Array &$arr) {
    $i = 0;
    $l = count($arr);
    do {
        if ( NULL === @$arr[$i] )
            return FALSE;
        ++$i;
    } while ($i < $l);
    return TRUE;
}

// deep reference reliance
function method_7(Array &$arr) {
    return array_keys(array_values($arr)) === array_keys($arr);
}


// organic (guessing + array_values)
function method_8(Array &$arr) {
    reset($arr);
    if ( key($arr) !== 0 )
        return FALSE;

    end($arr);
    if ( key($arr) !== count($arr)-1 )
        return FALSE;

    return array_values($arr) === $arr;
}

function benchmark(Array &$methods, Array &$target, $expected){    
    foreach($methods as $method){
        $start = microtime(true);
        for ($i = 0; $i < 2000; ++$i) {
            //$dummy = call_user_func($method, $target);
            if ( $method($target) !== $expected ) {
                echo "Method $method is disqualified for returning an incorrect result.\n";
                unset($methods[array_search($method,$methods,true)]);
                $i = 0;
                break;
            }
        }
        if ( $i != 0 ) {
            $end = microtime(true);
            echo "Time taken with $method = ".round(($end-$start)*1000.0,3)."ms\n";
        }
    }
}



$true_targets = [
    'Giant array' => range(0, 500),
    'Tiny array' => range(0, 20),
];


$g = range(0,10);
unset($g[0]);

$false_targets = [
    'Large array 1' => range(0, 100) + ['a'=>'a'] + range(101, 200),
    'Large array 2' => ['a'=>'a'] + range(0, 200),
    'Tiny array' => range(0, 10) + ['a'=>'a'] + range(11, 20),
    'Gotcha array' => $g,
];

$methods = [
    'method_1',
    'method_3',
    'method_4',
    'method_5',
    'method_6',
    'method_7',
    'method_8'
];


foreach($false_targets as $targetName => $target){
    echo "==== Benchmark using $targetName expecing FALSE ====\n";
    benchmark($methods, $target, false);
    echo "\n";
}
foreach($true_targets as $targetName => $target){
    echo "==== Benchmark using $targetName expecting TRUE ====\n";
    benchmark($methods, $target, true);
    echo "\n";
}
Panhellenic answered 6/10, 2008 at 7:1 Comment(0)
R
3

A lot of the solutions here are elegant and pretty, but don't scale well, and are memory intensive or CPU intensive. Most are creating 2 new data points in memory with this solution from both sides of the comparison. The larger the array the harder and longer the process and memory used, and you lose the benefit of short circuit evaluation. I Did some testing with a few different ideas. Trying to avoid array_key_exists as it is costly, and also avoiding creating new large datasets to compare. I feel this is a simple way to tell if an array is sequential.

public function is_sequential( $arr = [] ){
    if( !is_array( $arr ) || empty( $arr ) ) return false;

    $i = 0;

    $total = count( $arr );

    foreach( $arr as $key => $value ) if( $key !== $i++ ) return false;

    return true;
}

You run a single count on the main array and store a single integer. You then loop through the array and check for an exact match while iterating the counter. You should have from 1 to count. If it fails it will short circuit out which gives you performance boost when it is false.

Originally I did this with a for loop and checking for isset( $arr[$i] ) but this will not detect null keys which requires array_key_exists, and as we know that is the worst function to use for speed.

Constantly updating variables via foreach to check along with the iterator never growing past it's integer size let's PHP use it's built in memory optimization, caching and garbage collection to keep you at very low resource usage.

Also, I will argue that using array_keys in a foreach is silly when you can simply run $key => $value and check the key. Why create the new data point? Once you abstract away the array keys you've consumed more memory immediately.

Remarque answered 6/10, 2008 at 7:1 Comment(0)
M
3

answers are already given but there's too much disinformation about performance. I wrote this little benchmark script that shows that the foreach method is the fastest.

Disclaimer: following methods were copy-pasted from the other answers

<?php

function method_1(Array &$arr) {
    return $arr === array_values($arr);
}

function method_2(Array &$arr) {
    for (reset($arr), $i = 0; key($arr) !== $i++; next($arr));
    return is_null(key($arr));
}

function method_3(Array &$arr) {
    return array_keys($arr) === range(0, count($arr) - 1);
}

function method_4(Array &$arr) {
    $idx = 0;
    foreach( $arr as $key => $val ){
        if( $key !== $idx )
            return FALSE;
        $idx++;
    }
    return TRUE;
}




function benchmark(Array $methods, Array &$target){    
    foreach($methods as $method){
        $start = microtime(true);
        for ($i = 0; $i < 1000; $i++)
            $dummy = call_user_func($method, $target);

        $end = microtime(true);
        echo "Time taken with $method = ".round(($end-$start)*1000.0,3)."ms\n";
    }
}



$targets = [
    'Huge array' => range(0, 30000),
    'Small array' => range(0, 1000),
];
$methods = [
    'method_1',
    'method_2',
    'method_3',
    'method_4',
];
foreach($targets as $targetName => $target){
    echo "==== Benchmark using $targetName ====\n";
    benchmark($methods, $target);
    echo "\n";
}

results:

==== Benchmark using Huge array ====
Time taken with method_1 = 5504.632ms
Time taken with method_2 = 4509.445ms
Time taken with method_3 = 8614.883ms
Time taken with method_4 = 2720.934ms

==== Benchmark using Small array ====
Time taken with method_1 = 77.159ms
Time taken with method_2 = 130.03ms
Time taken with method_3 = 160.866ms
Time taken with method_4 = 69.946ms
Madalynmadam answered 6/10, 2008 at 7:1 Comment(0)
E
3

By using xarray PHP extension

You can do this very fast (about 30+ times faster in PHP 5.6):

if (array_is_indexed($array)) {  }

Or:

if (array_is_assoc($array)) {  }
Erdmann answered 6/10, 2008 at 7:1 Comment(0)
D
3

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:

function isNumericArray($array) {
    $count = count($array);
    for ($i = 0; $i < $count; $i++) {
        if (!isset($array[$i])) {
            return FALSE;
        }
    }
    return TRUE;
}

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.

Deckert answered 6/10, 2008 at 7:1 Comment(2)
one more point. array in form [1,2,null,4] will fail, but it is correct array. so i've added some enhancement at https://mcmap.net/q/53406/-how-to-check-if-php-array-is-associative-or-sequential with addition array_key_exists check)Corydalis
-1; isset() is the wrong tool here because it will return false if the value is set but is null, as pointed out by @lazycommit.Drugge
C
2

One more fast from source. Fit encoding of json_encode (and bson_encode). So has javascript Array compliance.

function isSequential($value){
    if(is_array($value) || ($value instanceof \Countable && $value instanceof \ArrayAccess)){
        for ($i = count($value) - 1; $i >= 0; $i--) {
            if (!isset($value[$i]) && !array_key_exists($i, $value)) {
                return false;
            }
        }
        return true;
    } else {
        throw new \InvalidArgumentException(
            sprintf('Data type "%s" is not supported by method %s', gettype($value), __METHOD__)
        );
    }
}
Corydalis answered 6/10, 2008 at 7:1 Comment(7)
Why isset and array_key_exists? wouldn't the latter be enough?Instauration
@Instauration yes, it would - the isset() check here is completely redundant.Drugge
@mcfedr, @mark-amery because of performance reasons. isset() is faster than array_key_exists(). see ilia.ws/archives/…Corydalis
@Corydalis Its going to depend on your array then on whether its better with or without, not that its likely to have an array with lots of nulls, but then its also not that likely you have array large enough that there would be noticeable performance difference by using both checksInstauration
@Instauration agree. bad data structure control means pure design and bad code smell. So, the thread is all about :)Corydalis
It's true the whole question is on the premise of badly designed codeInstauration
if you need to check if it would fit json_encode, you could simply check the first symbol of the string, returned by json_encode($your_arr) -- whether it's [ or { ;-)Pironi
I
2

My solution:

function isAssociative(array $array)
{
    return array_keys(array_merge($array)) !== range(0, count($array) - 1);
}

array_merge on a single array will reindex all integer keys, but not other. For example:

array_merge([1 => 'One', 3 => 'Three', 'two' => 'Two', 6 => 'Six']);

// This will returns [0 => 'One', 1 => 'Three', 'two' => 'Two', 2 => 'Six']

So if a list (a non-associative array) is created ['a', 'b', 'c'] then a value is removed unset($a[1]) then array_merge is called, the list is reindexed starting from 0.

Inherence answered 6/10, 2008 at 7:1 Comment(1)
-1; this is O(n) in additional memory used (since it created multiple new arrays with as many elements as $array), the answer doesn't address the ambiguity of the question that was asked nor explain exactly how it's defining a list / non-associative array, and even if neither of these points were true it's unclear that this adds any value compared to other answers already posted.Drugge
D
2

I think the definition of a scalar array will vary by application. That is, some applications will require a more strict sense of what qualifies as a scalar array, and some applications will require a more loose sense.

Below I present 3 methods of varying strictness.

<?php
/**
 * Since PHP stores all arrays as associative internally, there is no proper
 * definition of a scalar array.
 * 
 * As such, developers are likely to have varying definitions of scalar array,
 * based on their application needs.
 * 
 * In this file, I present 3 increasingly strict methods of determining if an
 * array is scalar.
 * 
 * @author David Farrell <[email protected]>
 */

/**
 * isArrayWithOnlyIntKeys defines a scalar array as containing
 * only integer keys.
 * 
 * If you are explicitly setting integer keys on an array, you
 * may need this function to determine scalar-ness.
 * 
 * @param array $a
 * @return boolean
 */ 
function isArrayWithOnlyIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    foreach ($a as $k => $v)
        if (!is_int($k))
            return false;
    return true;
}

/**
 * isArrayWithOnlyAscendingIntKeys defines a scalar array as
 * containing only integer keys in ascending (but not necessarily
 * sequential) order.
 * 
 * If you are performing pushes, pops, and unsets on your array,
 * you may need this function to determine scalar-ness.
 * 
 * @param array $a
 * @return boolean
 */ 
function isArrayWithOnlyAscendingIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    $prev = null;
    foreach ($a as $k => $v)
    {
        if (!is_int($k) || (null !== $prev && $k <= $prev))
            return false;
        $prev = $k;
    }
    return true;
}

/**
 * isArrayWithOnlyZeroBasedSequentialIntKeys defines a scalar array
 * as containing only integer keys in sequential, ascending order,
 * starting from 0.
 * 
 * If you are only performing operations on your array that are
 * guaranteed to either maintain consistent key values, or that
 * re-base the keys for consistency, then you can use this function.
 * 
 * @param array $a
 * @return boolean
 */
function isArrayWithOnlyZeroBasedSequentialIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    $i = 0;
    foreach ($a as $k => $v)
        if ($i++ !== $k)
            return false;
    return true;
}
Dominga answered 6/10, 2008 at 7:1 Comment(0)
W
2

This would work too (demo):

function array_has_numeric_keys_only(array $array)
{
    try {
        SplFixedArray::fromArray($array, true);
    } catch (InvalidArgumentException $e) {
        return false;
    }
    return true;
}

Please note that the main point of this answer is to inform you about the existence of SplFixedArray and not to encourage you to use Exceptions for these kinds of tests.

Walkling answered 6/10, 2008 at 7:1 Comment(0)
S
2
<?php

function is_list($array) {
    return array_keys($array) === range(0, count($array) - 1);
}

function is_assoc($array) {
    return count(array_filter(array_keys($array), 'is_string')) == count($array);
}

?>

Both of these examples, which scored the most points do not work correctly with arrays like $array = array('foo' => 'bar', 1)

Stouthearted answered 6/10, 2008 at 7:1 Comment(1)
+1 Your is_list() is IMO the best answer. Some people don't have a clue about time & space complexity, and native vs PHP scripted function...Felting
M
2

Here's the method I use:

function is_associative ( $a )
{
    return in_array(false, array_map('is_numeric', array_keys($a)));
}

assert( true === is_associative(array(1, 2, 3, 4)) );

assert( false === is_associative(array('foo' => 'bar', 'bar' => 'baz')) );

assert( false === is_associative(array(1, 2, 3, 'foo' => 'bar')) );

Note that this doesn't account for special cases like:

$a = array( 1, 2, 3, 4 );

unset($a[1]);

assert( true === is_associative($a) );

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

Mccreery answered 6/10, 2008 at 7:1 Comment(0)
H
2

Could this be the solution?

  public static function isArrayAssociative(array $array) {
      reset($array);
      return !is_int(key($array));
  }

The caveat is obviously that the array cursor is reset but I'd say probably the function is used before the array is even traversed or used.

Halloo answered 6/10, 2008 at 7:1 Comment(6)
This function returns false for both array("a", "b") and array("a", "b" => "B") as it only checks the first key. BTW, is_long is just an alias of is_int.Cleft
quite frankly I think this would be very effective in the vast majority of cases, and is far more efficient than the alternatives. If you understand the consequences of this method, and realize it will work for you, it's likely the best choice.Rigid
This is simply wrong; it only looks at the first key.Drugge
@MarkAmery the question asked how to differentiate purely sequential arrays from purely associative arrays. This answer does exactly that and is the most efficient of them all. Having undefined behavior for mixed arrrays is perfectly fine in the context of the question. +1Aundreaaunson
@Aundreaaunson I don't think most people would agree with you classifying, say, [7 => 'foo', 2 => 'bar'] as a "mixed" array that is partly but not "purely" sequential. That seems like a plainly incorrect use of words to me.Drugge
@MarkAmery Is your example a sequential numeric array? No. Is it an associative array (with string keys)? No. Therefore it's out of scope for this answer, IMHO. You can think about the output of yaml_parse_file() if you want (and the usual way to write YAML files.) You either get sequential, numeric arrays (if you start your sections with -) or string-based associative arrays (if you start your sections with name:.) No in-between.Aundreaaunson
G
1

Just adding my two cents, and I think it should be pretty efficient based on @nonsensei 's benchmarks as well as being clearly legible:

function is_associative(array $array): bool
{
    foreach ($array as $key => $value)
    {
        if (!is_string($key)) return false;
    }
    return true;
}
Gaudery answered 6/10, 2008 at 7:1 Comment(0)
P
1

Sometimes you can get away with only checking if the first array's Key is 0.

$isSequential = array_keys($arr)[0] === 0

, or, faster, but more verbose version:

reset($arr); $isSequential = key($arr) === 0

Pironi answered 6/10, 2008 at 7:1 Comment(0)
C
1

This question is actually useless when it comes to array of php because with the nature of php an array should not have to be fully associative or indexing, it can be combination of both, the way user have define and assigned the value an array can be a combination of both. see the example below

$y= array(5);
$y["0x"]="n";
$y["vbg"]="12132";
$y[1] = "k";

var_dump($y); //this will output 4 element array

echo "</br>" .$y["0x"]."</br>".$y[0];

for($x=0;$x<sizeof($y);$x++){ // this will output all index elements & gives error after that
    echo "</br> index elements ".$y[$x];
}

so the correct question that has to ask is , is all the element in array are associative or index. if you really know that it will only be either associative or indexing not a combination of these two, you can just simply use this method to find wether it is an index or associative array.

function AssocTest(&$arr){
    if(is_array($arr)){

        reset($arr); // reset pointer to first element of array

        if(gettype(key($arr)) == "string"){ //get the type(nature) of first element key 
            return true;
        }else{
            return false;
        }
    }else{
        return false;
    }
}

you can use it as normal function

echo(AssocTest($y)?  "Associative array": "Not an Associative array/ Not an array at all");

and important thing to remember evan you have initialize an array as associative but the names that you have gave the associative array is just numbers it will treat as an index array when it being read by php if you have not explicitly gave the string names. take a look at the example below.

$y["0"]="n";
$y["1"]="12132";
$y["22"] = "k";

//both will get the same output
echo "<br/> s0 ".$y["22"];
echo "<br/> s0 ".$y[22];

for($x=0;$x<count($y);$x++){
   echo "<br/> arr ".$y[$x]; // this will output up to 2nd element and give an error after

}

so if you need to be sure all the elements of the array to be exactly indexed or either associative , there is no other way but go true all the elements and check each and every element key by generated index array as post by many people here.

function fullAssocTest(&$arr)
{
    if(is_array($arr)){
        return (array_keys($arr) !== range(0, count($arr) - 1));
    }
}

its less coding, but this thing is really process intensive and really un-necessary work.

Coreligionist answered 6/10, 2008 at 7:1 Comment(0)
G
1

Or you can just use this:

Arr::isAssoc($array)

which will check if array contains any non-numeric key or:

Arr:isAssoc($array, true)

to check if array is strictly sequencial (contains auto generated int keys 0 to n-1)

using this library.

Gynoecium answered 6/10, 2008 at 7:1 Comment(0)
S
0

I've come up with next method:

function isSequential(array $list): bool
{
    $i = 0;
    $count = count($list);
    while (array_key_exists($i, $list)) {
        $i += 1;
        if ($i === $count) {
            return true;
        }
    }

    return false;
}


var_dump(isSequential(array())); // false
var_dump(isSequential(array('a', 'b', 'c'))); // true
var_dump(isSequential(array("0" => 'a', "1" => 'b', "2" => 'c'))); // true
var_dump(isSequential(array("1" => 'a', "0" => 'b', "2" => 'c'))); // true
var_dump(isSequential(array("1a" => 'a', "0b" => 'b', "2c" => 'c'))); // false
var_dump(isSequential(array("a" => 'a', "b" => 'b', "c" => 'c'))); // false

*Note empty array is not considered a sequential array, but I think it's fine since empty arrays is like 0 - doesn't matter it's plus or minus, it's empty.

Here are the advantages of this method compared to some listed above:

  • It does not involve copying of arrays (someone mentioned in this gist https://gist.github.com/Thinkscape/1965669 that array_values does not involve copying - what!?? It certainly does - as will be seen below)
  • It's faster for bigger arrays and more memory friendly at the same time

I've used benchmark kindly provided by Artur Bodera, where I changed one of the arrays to 1M elements (array_fill(0, 1000000, uniqid()), // big numeric array).

Here are the results for 100 iterations:

PHP 7.1.16 (cli) (built: Mar 31 2018 02:59:59) ( NTS )

Initial memory: 32.42 MB
Testing my_method (isset check) - 100 iterations
  Total time: 2.57942 s
  Total memory: 32.48 MB

Testing method3 (array_filter of keys) - 100 iterations
  Total time: 5.10964 s
  Total memory: 64.42 MB

Testing method1 (array_values check) - 100 iterations
  Total time: 3.07591 s
  Total memory: 64.42 MB

Testing method2 (array_keys comparison) - 100 iterations
  Total time: 5.62937 s
  Total memory: 96.43 MB

*Methods are ordered based on their memory consumption

**I used echo " Total memory: " . number_format(memory_get_peak_usage()/1024/1024, 2) . " MB\n"; to display memory usage

Supersonics answered 6/10, 2008 at 7:1 Comment(3)
if you /1024 the unit is MiB (Mebibyte) if you /1000 the unit is MB (Megabyte). Mega === 1000000, in software engineering and in phsyics, on the moon and on the earth and also inside your computer. Mega is never 1024*1024. And Kilo is always 1000, not 1024.Oft
wow @DanFromGermany, thanks for you incredibly useful comment! That is good to know. PS. by the way in fact Mega is exactly 1024*1024 inside my computer, it's a non standard one :)Supersonics
Nice to do a benchmark, but have a look at https://mcmap.net/q/53406/-how-to-check-if-php-array-is-associative-or-sequential where there is no call to array_key_exists()Hooker
H
0

Modification on the most popular answer.
This takes a little more processing, but is more accurate.

<?php
//$a is a subset of $b
function isSubset($a, $b)
{
    foreach($a =>$v)
        if(array_search($v, $b) === false)
            return false;

    return true;

    //less effecient, clearer implementation. (uses === for comparison)
    //return array_intersect($a, $b) === $a;
}

function isAssoc($arr)
{
    return !isSubset(array_keys($arr), range(0, count($arr) - 1));
}

var_dump(isAssoc(array('a', 'b', 'c'))); // false
var_dump(isAssoc(array(1 => 'a', 0 => 'b', 2 => 'c'))); // false
var_dump(isAssoc(array("0" => 'a', "1" => 'b', "2" => 'c'))); // false 
//(use === in isSubset to get 'true' for above statement)
var_dump(isAssoc(array("a" => 'a', "b" => 'b', "c" => 'c'))); // true
?>
Hepatica answered 6/10, 2008 at 7:1 Comment(1)
-1; this will take O(n²) time to complete given a sequential array of size n. That's going to be horribly inefficient for large enough arrays.Drugge
F
0

I compare the difference between the keys of the array and the keys of the result of array_values() of the array, which will always be an array with integer indices. If the keys are the same, it's not an associative array.

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}
Finnell answered 6/10, 2008 at 7:1 Comment(1)
-1; this uses O(n) additional memory when $array has n items, and writing (someboolean) ? false : true instead of !someboolean is horrible and gratuitously verbose.Drugge
O
0

Yet another way to do this.

function array_isassociative($array)
{
    // Create new Array,  Make it the same size as the input array
    $compareArray = array_pad(array(), count($array), 0);

    // Compare the two array_keys
    return (count(array_diff_key($array, $compareArray))) ? true : false;

}
Olivas answered 6/10, 2008 at 7:1 Comment(0)
D
0
function is_associative($arr) {
  return (array_merge($arr) !== $arr || count(array_filter($arr, 'is_string', ARRAY_FILTER_USE_KEY)) > 0);
}
Downhaul answered 6/10, 2008 at 7:1 Comment(5)
implode takes 2 arguments, plus, that function would return false for an array defined like this: $x = array("1" => "b", "0" => "a");Remanent
The glue parameter of implode() became optional in PHP 4.3.0. Your example array -- $x = array("1" => "b", "0" => "a"); -- has an associative index of non-sequential strings. is_associative() will return true for that array, as expected.Downhaul
I like this one. The first conditional will detect associative arrays where numeric indices are not numerically sequential, or where the first index is not "0", because array_merge will re-index keys of a numerically indexed (but possibly associative) array.Checkerwork
-1; this uses O(n) additional memory when $arr has n items, plus there's no explanation of what it does nor exploration of the ambiguity of the question that was asked. It also treats an array that has sequential numeric keys and the empty string as a key as non-associative, which defies any sane definition one might draw up between an 'associative' and 'sequential' array.Drugge
@MarkAmery Interesting point about the empty string as a key.Downhaul
H
-1
/*
iszba - Is Zero Based Array

Detects if an array is zero based or not.

PARAMS:
    $chkvfnc
        Callback in the loop allows to check the values of each element.
        Signature:
            bool function chkvfnc($v);
            return:
                true    continue looping
                false   stop looping; iszba returns false too.

NOTES:
○ assert: $array is an array.
○ May be memory efficient;
  it doesn't get extra arrays via array_keys() or ranges() into the function.
○ Is pretty fast without a callback.
○ With callback it's ~2.4 times slower.
*/
function iszba($array, $chkvfnc=null){

    $ncb = !$chkvfnc;
    $i = 0;

    foreach($array as $k => $v){
        if($k === $i++)
            if($ncb || $chkvfnc($v))
                continue;

        return false;
    }

    return true;
}

• Without callback it is ~30% faster than current leading answer, and possibly more memory efficient.

• Just negate the answer to know if the array should be considered associative.

Heterochromatin answered 6/10, 2008 at 7:1 Comment(0)
B
-1

Checking if array has all assoc-keys. With using stdClass & get_object_vars ^):

$assocArray = array('fruit1' => 'apple', 
                    'fruit2' => 'orange', 
                    'veg1' => 'tomato', 
                    'veg2' => 'carrot');

$assoc_object = (object) $assocArray;
$isAssoc = (count($assocArray) === count (get_object_vars($assoc_object)));  
var_dump($isAssoc); // true

Why? Function get_object_vars returns only accessible properties (see more about what is occuring during converting array to object here). Then, just logically: if count of basic array's elements equals count of object's accessible properties - all keys are assoc.

Few tests:

$assocArray = array('apple', 'orange', 'tomato', 'carrot');
$assoc_object = (object) $assocArray; 
$isAssoc = (count($assocArray) === count (get_object_vars($assoc_object)));
var_dump($isAssoc); // false 
//...

$assocArray = array( 0 => 'apple', 'orange', 'tomato', '4' => 'carrot');
$assoc_object = (object) $assocArray; 
$isAssoc = (count($assocArray) === count (get_object_vars($assoc_object)));
var_dump($isAssoc); // false 

//... 
$assocArray = array('fruit1' => 'apple', 
                    NULL => 'orange', 
                    'veg1' => 'tomato', 
                    'veg2' => 'carrot');

$assoc_object = (object) $assocArray;
$isAssoc = (count($assocArray) === count (get_object_vars($assoc_object)));  
var_dump($isAssoc); //false

Etc.

Barkley answered 6/10, 2008 at 7:1 Comment(1)
This not work. Proof eval.in/859508 $asocArray is array with two arrays. Return true. Other proofs for others exaqmple also not work how to your latets example eval.in/859507 return trueHartzell
L
-1

Improvement from Mark Amery

function isAssoc($arr)
{
    // Is it set, is an array, not empty and keys are not sequentialy numeric from 0
    return isset($arr) && is_array($arr) && count($arr)!=0 && array_keys($arr) !== range(0, count($arr) - 1);
}

This tests if variable exists, if it is an array, if it is not an empty array and if the keys are not sequential from 0.

To see if the array is associative

if (isAssoc($array)) ...

To see if it numeric

if (!isAssoc($array)) ...
Larimore answered 6/10, 2008 at 7:1 Comment(2)
Wait, what, where did I contribute this? Or did you mean to say "Improvement on Mark Amery", as in an improvement on the accepted answer that is attributed to me? Please be aware, in the latter case, that I didn't author that answer - my edits to it have simply caused the authorship attribution algorithm for Community Wiki posts to put my name on it.Drugge
isset() is entirely useless here, right? $arr is unconditionally declared in the function signature, the $arr is checked for being an array, so null is no concern.Youlandayoulton
H
-1

Actually, I found myself in a similar situation trying to take an array and parse it into XML. XML element names cannot begin with numbers -- and the code snippets I found did not correctly deal with arrays with numeric indexes.

Details on my particular situation are below

The answer provided above by @null ( http:// stackoverflow .com/a/173589/293332 ) was actually pretty darn close. I was dismayed that it got voted down tho: Those who do not understand regex lead very frustrating lives.

Anyway, based upon his answer, here is what I ended up with:

/** 
 * Checks if an array is associative by utilizing REGEX against the keys
 * @param   $arr    <array> Reference to the array to be checked
 * @return  boolean
 */     
private function    isAssociativeArray( &$arr ) {
    return  (bool)( preg_match( '/\D/', implode( array_keys( $arr ) ) ) );
}

See the PCRE Escape Sequences and PCRE Syntax pages for further details.

My Particular Situation

Here is an example array that I am dealing with:

Case A
return  array(
    "GetInventorySummary"  => array(
        "Filters"  => array( 
            "Filter"  => array(
                array(
                    "FilterType"  => "Shape",
                    "FilterValue"  => "W",
                ),
                array(
                    "FilterType"  => "Dimensions",
                    "FilterValue"  => "8 x 10",
                ),
                array(
                    "FilterType"  => "Grade",
                    "FilterValue"  => "A992",
                ),
            ),
        ),
        "SummaryField"  => "Length",
    ),
);

The catch is that the filter key is variable. For example:

Case B
return  array(
    "GetInventorySummary"  => array(
        "Filters"  => array( 
            "Filter"  => array(
                "foo"   =>  "bar",
                "bar"   =>  "foo",
            ),
        ),
        "SummaryField"  => "Length",
    ),
);

Why I Need Assoc. Array Checker

If the array I am transforming is like Case A, what I want returned is:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GetInventorySummary>
    <Filters>
        <Filter>
            <FilterType>Shape</FilterType>
            <FilterValue>W</FilterValue>
        </Filter>
        <Filter>
            <FilterType>Dimensions</FilterType>
            <FilterValue>8 x 10</FilterValue>
        </Filter>
        <Filter>
            <FilterType>Grade</FilterType>
             <FilterValue>A992</FilterValue>
        </Filter>
    </Filters>
    <SummaryField>Length</SummaryField>
</GetInventorySummary>

... However, if the array I am transforming is like Case B, what I want returned is:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GetInventorySummary>
    <Filters>
        <Filter>
            <foo>bar</foo>
            <bar>foo</bar>
        </Filter>
    </Filters>
    <SummaryField>Length</SummaryField>
</GetInventorySummary>
Harrell answered 6/10, 2008 at 7:1 Comment(1)
This isAssociativeArray() returns false for array(4=>"four",9=>"nine"), array("002"=>"two","007"=>"james") and array("a", ""=>"empty", "b"), which are clearly associative.Cleft
K
-1

My solution is to get keys of an array like below and check that if the key is not integer:

private function is_hash($array) {
    foreach($array as $key => $value) {
        return ! is_int($key);
    }
    return false;
}

It is wrong to get array_keys of a hash array like below:

array_keys(array(
       "abc" => "gfb",
       "bdc" => "dbc"
       )
);

will output:

array(
       0 => "abc",
       1 => "bdc"
)

So, it is not a good idea to compare it with a range of numbers as mentioned in top rated answer. It will always say that it is a hash array if you try to compare keys with a range.

Koss answered 6/10, 2008 at 7:1 Comment(2)
The question is how to check if an array is sequential though. The array array(1 => 'foo', 0 => 'bar') is not sequential but will pass your test. For why that makes a difference, try json_encode($array) with sequential and associative arrays.Dock
yes, i guess i got pretty confused and stuck with the above answers. Which kept comparing array_keys with a range and thought they will have an output which is comparison whether it is a hash or not. So my answer is to them and also to whom thinks that array_keys gives values are sequential. that's all. And also function name is is_hash so yes it doesn't tell you whether it is sequential or notSebaceous
B
-1

I met this problem once again some days ago and i thought to take advantage of the array_merge special property:

If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended. Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array. So why not to use:

function Is_Indexed_Arr($arr){
    $arr_copy = $arr;
    if((2*count($arr)) == count(array_merge($arr, $arr_copy))){
        return 1;
    }
    return 0;
}
Bob answered 6/10, 2008 at 7:1 Comment(0)
O
-1

Unless PHP has a builtin for that, you won't be able to do it in less than O(n) - enumerating over all the keys and checking for integer type. In fact, you also want to make sure there are no holes, so your algorithm might look like:

for i in 0 to len(your_array):
    if not defined(your-array[i]):
        # this is not an array array, it's an associative array :)

But why bother? Just assume the array is of the type you expect. If it isn't, it will just blow up in your face - that's dynamic programming for you! Test your code and all will be well...

Osmanli answered 6/10, 2008 at 7:1 Comment(1)
Normally just assuming the array is the desired type would be the way to go. But in my case I'm looping through a multidimensional array and am formatting the output depending on which type of array a given node is.Salverform
H
-2

I'm surprised no one has mentioned array_key_first()

For your test cases:

$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
$isIndexedArray = is_int( array_key_first($sequentialArray) ); // true

whereas

$assocArray = array('fruit1' => 'apple', 
                'fruit2' => 'orange', 
                'veg1' => 'tomato', 
                'veg2' => 'carrot');

$isIndexedArray = is_int( array_key_first($assocArray) ); // false

Read more about this function here.

Hair answered 6/10, 2008 at 7:1 Comment(1)
This won't work for mixed arrays when the first index is sequential, but the following elements have associative indexes.Maintain
H
-2

Check if the data type is array, then json encode then decode the data and check if the new data type is object.

public function is_assoc_array($array)
{
    return is_array($array)
           && is_object(json_decode(json_encode($array)));
}

Some examples

echo is_assoc_array(['one', 'two', 'three']) ? 'Yes' : 'No'); \\No
    
echo is_assoc_array(['one' => 'one', 'two' => 'two', 'three' => 'three']) ? 'Yes' : 'No'; \\Yes
    
echo is_assoc_array(['1' => 'one', '2' => 'two', '3' => 'three']) ? 'Yes' : 'No'; \\Yes
    
echo is_assoc_array(['0' => 'one', '1' => 'two', '2' => 'three']) ? 'Yes' : 'No'; \\No

There was a similar solution by @devios1 in one of the answers but this was just another way using the inbuilt json related functions of PHP. I haven't checked how this solution fairs in terms of performance compared to other solutions that have been posted here.

Hepplewhite answered 6/10, 2008 at 7:1 Comment(0)
S
-2
function is_array_assoc($foo) {
    if (is_array($foo)) {
        return (count(array_filter(array_keys($foo), 'is_string')) > 0);
    }
    return false;
}
Skittish answered 6/10, 2008 at 7:1 Comment(1)
-1 for the total lack of explanation. Dumping another code sample on a question that has had 42 answers without any explanation of why to prefer it over the alternatives helps absolutely nobody. Also, given the question's ambiguity and the arguments that have raged over it in the comments, some explanation of exactly how you're defining a "associative" or "sequential" array seems necessary here.Drugge
E
-2

Simple and performance friendly solution which only checks the first key.

function isAssoc($arr = NULL)
{
    if ($arr && is_array($arr))
    {
        foreach ($arr as $key => $val)
        {
            if (is_numeric($key)) { return true; }

            break;
        }
    }

    return false;
}
Exequatur answered 6/10, 2008 at 7:1 Comment(1)
This function returns true for both array("a", "b") and array("a", "b" => "B") as it only checks the first key (note the return and the break).Cleft
H
-2

Best function to detect associative array (hash array)

<?php
function is_assoc($arr) { return (array_values($arr) !== $arr); }
?>
Harberd answered 6/10, 2008 at 7:1 Comment(3)
fails for single element associative arraysEarthaearthborn
Isn't this a duplicate answer ?Bignonia
Can you give an example, Jinu? I don't see this behavior. (Although I use == not ===; I don't know why so many use ===.)Coy
P
-2

Another variant not shown yet, as it's simply not accepting numerical keys, but I like Greg's one very much :

 /* Returns true if $var associative array */  
  function is_associative_array( $array ) {  
    return is_array($array) && !is_numeric(implode('', array_keys($array)));  
  }
Potbellied answered 6/10, 2008 at 7:1 Comment(3)
This function returns false for array(2=>'a',3=>'b'), array('a','b'), array("0x"=>'a','f'=>'g'), array("90"=>'a',"17"=>'b'), array(""=>'b',20=>'c').Cleft
@Pang: if you could read : "it's simply not accepting numerical keys,", you could just remove the downvote. Thx.Potbellied
Your is_associative_array() is returning false for associative arrays such as array("0x"=>'a','f'=>'g') and array(""=>'b',20=>'c'). Now, I am confused.Cleft
E
-2
function isAssoc($arr)
{
    $a = array_keys($arr);
    for($i = 0, $t = count($a); $i < $t; $i++)
    {
        if($a[$i] != $i)
        {
            return false;
        }
    }
    return true;
}
Exoskeleton answered 6/10, 2008 at 7:1 Comment(2)
this assumes the array is indexed from 0 which is not necessarily true and will give wrong results for arrays like [10=>'x', 20=>'y']Walkling
This function returns true for both array("a"=>"b") and array("a","b").Cleft
R
-2

One cheap and dirty way would be to check like this:

isset($myArray[count($myArray) - 1])

...you might get a false positive if your array is like this:

$myArray = array("1" => "apple", "b" => "banana");

A more thorough way might be to check the keys:

function arrayIsAssociative($myArray) {
    foreach (array_keys($myArray) as $ind => $key) {
        if (!is_numeric($key) || (isset($myArray[$ind + 1]) && $myArray[$ind + 1] != $key + 1)) {
            return true;
        }
    }
    return false;
}
// this will only return true if all the keys are numeric AND sequential, which
// is what you get when you define an array like this:
// array("a", "b", "c", "d", "e");

or

function arrayIsAssociative($myArray) {
    $l = count($myArray);
    for ($i = 0; $i < $l, ++$i) {
        if (!isset($myArray[$i])) return true;
    }
    return false;
}
// this will return a false positive on an array like this:
$x = array(1 => "b", 0 => "a", 2 => "c", 4 => "e", 3 => "d");
Remanent answered 6/10, 2008 at 7:1 Comment(2)
+1 for the isset method. Yes, it's dirty, but it's the only method that's O(1) instead of O(n).Contrapuntist
The thorough arrayIsAssociative() returns true for both array("a", "b", "c") and array("a", "b"=>"b", "c"), but false for both array("a") and array(2=>"a").Cleft
T
-3

For this purpose, you can use the fact that an array is not assoc. For this, the required array keys must be extracted first, then you must create another numerical array equal to the number of items in the first array, when the first array is different from the second array, a numerical array is no longer answered.

/**
 * check is not assoc array
 *
 * @param array $array
 *
 * @return bool
 */
function isNotAssoc(array $array): bool
{
    if(empty($array)) {
        return false;
    }

    return empty(array_diff(array_keys($array), range(0, count($array) - 1)));
}
Towne answered 6/10, 2008 at 7:1 Comment(6)
Can you please add some explanation, why this answer is different or better than all the others?Blue
Why would ANYONE want to use this while PHP has had array_is_list() for years now. See this earlier, superior answer: https://mcmap.net/q/53406/-how-to-check-if-php-array-is-associative-or-sequential Please only post new content if you have something unique and valuable to share.Youlandayoulton
Hey this code is for php 8 and below and I was looking for it for a while @YoulandayoultonTowne
empty() is an inappropriate call when a variable is guaranteed to be declared. If you executing a "diff" on "keys" call array_diff_key(). More specifically, return !array_diff_key($array, range(1, count($array))); BUT this does not check key order AND this technique is not optimized for memory usage or computational time. It must double the memory of the input array and must perform sorting filtration on the entire payload. In other words, this script does not enjoy the performance boost of an early exit. I don't recommend this script in any PHP version.Youlandayoulton
Please read the top voted answer on this topic, then ask yourself if your answer offers any advantage. Spoiler: it doesn't.Youlandayoulton
Go ahead and use the upper ones :)Towne
C
-3

function is_assoc(array $array): bool
{
    foreach ($array as $iValue) {
        if (is_array($iValue)) {
            return  true;
        }
    }
    return false;

}

$d= is_assoc(["id",2,3]);

var_dump($d);
Coumarin answered 6/10, 2008 at 7:1 Comment(5)
Why is this the answer to the question?Medea
because that is the most simple methodKatharyn
...because that is the most simple method... It is not recommended to post code-only answers, answers should provide more explanation about the code to make it the answer more useful and are more likely to attract upvotesMedea
This checks whether the array contains an array as value, but does not differentiate between associate and sequential arrays. One way to see that something is off is that it returns the same exact answer false for the two test arrays provided in the question.Aparicio
@dılosürücü So, what's abount is_assoc([[], []])?Keloid
P
-3

In simple way you can check is array is associative or not by below steps

  1. convert all keys of array into one array by using array_keys()
  2. filter out non numeric key from array using array_filter() and is_numeric()
  3. compare number of elements in filtered array and actual array, If number of elements are not equals in both array then it is associative array.

Function for above step is as below.

 function isAssociative(array $array)
    {
        return count(array_filter(array_keys($array), function($v){return is_numeric($v);})) !== count($array));
    }
Paisa answered 6/10, 2008 at 7:1 Comment(0)
V
-3

I just use the key() function. Observe:

<?php
var_dump(key(array('hello'=>'world', 'hello'=>'world'))); //string(5) "hello"
var_dump(key(array('world', 'world')));                  //int(0)
var_dump(key(array("0" => 'a', "1" => 'b', "2" => 'c'))); //int(0) who makes string sequetial keys anyway????
?>

Thus, just by checking for false, you can determine whether an array is associative or not.

Valdis answered 6/10, 2008 at 7:1 Comment(2)
No. var_dump((bool)key(array(1=>"foo"))); returns true. -1.Hurst
var_dump((bool)key(array("a"=>"foo"))) returns true; var_dump((bool)key(array(""=>"foo"))) returns false. Also, both var_dump((bool)key(array("foo","bar"))) and var_dump((bool)key(array("0"=>"foo","a"=>"bar"))) returns false.Cleft
S
-5

If your looking for just non-numeric keys (no matter the order) then you may want to try

function IsAssociative($array)
{
    return preg_match('/[a-z]/i', implode(array_keys($array)));
}
Soda answered 6/10, 2008 at 7:1 Comment(1)
-1 for missing your apostrophe. Oh, and test with array("@"=>"foo");. And ... preg, really?Hurst

© 2022 - 2024 — McMap. All rights reserved.