169
  1. What is the most efficient way to check if an array is a flat array of primitive values or if it is a multidimensional array?
  2. Is there any way to do this without actually looping through an array and running is_array() on each of its elements?
2
  • 11
    It's worth pointing out that PHP does not have true multi-dimensional arrays -- just simple associative array's of values. So your question is really asking "is there a non-scalar value in my array"? Commented May 17, 2010 at 2:50
  • 28
    Actually... I don't think that's worth pointing out at all. Commented Jul 26, 2013 at 2:14

14 Answers 14

238

Use count() twice; one time in default mode and one time in recursive mode. If the values match, the array is not multidimensional, as a multidimensional array would have a higher recursive count.

if (count($array) == count($array, COUNT_RECURSIVE)) 
{
  echo 'array is not multidimensional';
}
else
{
  echo 'array is multidimensional';
}

This option second value mode was added in PHP 4.2.0. From the PHP Docs:

If the optional mode parameter is set to COUNT_RECURSIVE (or 1), count() will recursively count the array. This is particularly useful for counting all the elements of a multidimensional array. count() does not detect infinite recursion.

However this method does not detect array(array()).

Sign up to request clarification or add additional context in comments.

2 Comments

As noted this does not work for elements with empty arrays
This answer is provably incorrect and the post score indicates that MANY researchers have been misled. 3v4l.org/ptGQ9
153

The short answer is no you can't do it without at least looping implicitly if the 'second dimension' could be anywhere. If it has to be in the first item, you'd just do

is_array($arr[0]);

But, the most efficient general way I could find is to use a foreach loop on the array, shortcircuiting whenever a hit is found (at least the implicit loop is better than the straight for()):

$ more multi.php
<?php

$a = array(1 => 'a',2 => 'b',3 => array(1,2,3));
$b = array(1 => 'a',2 => 'b');
$c = array(1 => 'a',2 => 'b','foo' => array(1,array(2)));

function is_multi($a) {
    $rv = array_filter($a,'is_array');
    if(count($rv)>0) return true;
    return false;
}

function is_multi2($a) {
    foreach ($a as $v) {
        if (is_array($v)) return true;
    }
    return false;
}

function is_multi3($a) {
    $c = count($a);
    for ($i=0;$i<$c;$i++) {
        if (is_array($a[$i])) return true;
    }
    return false;
}
$iters = 500000;
$time = microtime(true);
for ($i = 0; $i < $iters; $i++) {
    is_multi($a);
    is_multi($b);
    is_multi($c);
}
$end = microtime(true);
echo "is_multi  took ".($end-$time)." seconds in $iters times\n";

$time = microtime(true);
for ($i = 0; $i < $iters; $i++) {
    is_multi2($a);
    is_multi2($b);
    is_multi2($c);
}
$end = microtime(true);
echo "is_multi2 took ".($end-$time)." seconds in $iters times\n";
$time = microtime(true);
for ($i = 0; $i < $iters; $i++) {
    is_multi3($a);
    is_multi3($b);
    is_multi3($c);
}
$end = microtime(true);
echo "is_multi3 took ".($end-$time)." seconds in $iters times\n";
?>

$ php multi.php
is_multi  took 7.53565130424 seconds in 500000 times
is_multi2 took 4.56964588165 seconds in 500000 times
is_multi3 took 9.01706600189 seconds in 500000 times

Implicit looping, but we can't shortcircuit as soon as a match is found...

$ more multi.php
<?php

$a = array(1 => 'a',2 => 'b',3 => array(1,2,3));
$b = array(1 => 'a',2 => 'b');

function is_multi($a) {
    $rv = array_filter($a,'is_array');
    if(count($rv)>0) return true;
    return false;
}

var_dump(is_multi($a));
var_dump(is_multi($b));
?>

$ php multi.php
bool(true)
bool(false)

5 Comments

Good, with the caveat that I believe that your filtering line should have array_map("is_array",$a), not using is_array as a bareword.
Good catch, that sped up is_multi, but still not good enough to match foreach
It is worth noting that, as written, multi_3 will only work on zero-based non-associative arrays with no gaps in the indices, meaning it won't correctly identify any of these examples as multi-dimensional.
In function is_multi() optimize the code by doing return count($rv)>0
is_array(array_values($arr)[0]) as a workaround for customized keys.
27

For PHP 4.2.0 or newer:

function is_multi($array) {
    return (count($array) != count($array, 1));
}

2 Comments

Not working for array(array()) or array(array(), array()) either. Generally, if an inside array is empty then the recursive count will correctly add 0 for it, thus making it match the normal count.
This answer is provably unreliable. 3v4l.org/LLg2t
9

After PHP 7 you could simply do:

public function is_multi(array $array):bool
{
    return is_array($array[array_key_first($array)]);
}

1 Comment

You just check the first array element if it is an array. What if it is not but the 2nd element is an array? For example $array = ['0' => 0, '1' => ['0' => 1]]; This is a multidim array but your function says false.
6

You could look check is_array() on the first element, under the assumption that if the first element of an array is an array, then the rest of them are too.

3 Comments

That's actually a good point. In my particular case, it's an either/or situation since I am controlling the creation of the original array. I'll leave the question open for now in case there's a solution that might work more generally though.
Like this: if( is_array(current($arr)) ) { // is multidimensional }
This is only a valid option if the first level of the array has consistent data types.
4

I think you will find that this function is the simplest, most efficient, and fastest way.

function isMultiArray($a){
    foreach($a as $v) if(is_array($v)) return TRUE;
    return FALSE;
}

You can test it like this:

$a = array(1 => 'a',2 => 'b',3 => array(1,2,3));
$b = array(1 => 'a',2 => 'b');

echo isMultiArray($a) ? 'is multi':'is not multi';
echo '<br />';
echo isMultiArray($b) ? 'is multi':'is not multi';

3 Comments

if you're going to one-line it at least do the whole thing; foreach($a as $v) is_array($v) ? return TRUE : return FALSE;
@RobertPounder or even foreach($a as $v) return is_array($v) ? true : false;
Uuuuuuumm, no, RobertPounder and YassineSedrani. You can't one-liner it like that; that would create different logic. Returning on the first iteration does not check the whole array. You might as well just evaluate on the first element if you are going to unconditionally return early. No. For a fully reliable solution, you need to allow the possibility of iterating the full array as a pathway to determining the opposite data type.
4

Don't use COUNT_RECURSIVE

click this site for know why

use rsort and then use isset

function is_multi_array( $arr ) {
rsort( $arr );
return isset( $arr[0] ) && is_array( $arr[0] );
}
//Usage
var_dump( is_multi_array( $some_array ) );

2 Comments

$arr[0] could not be and array but $arr[1] could be an array
This answer has a larger time complexity than is necessary because sorting is more expensive than merely iterating every element in the array. I would not recommend this answer for any reason.
2

Even this works

is_array(current($array));

If false its a single dimension array if true its a multi dimension array.

current will give you the first element of your array and check if the first element is an array or not by is_array function.

1 Comment

That won't be reliable if you want to ensure that any other element isn't nested either.
1

You can also do a simple check like this:

$array = array('yo'=>'dream', 'mydear'=> array('anotherYo'=>'dream'));
$array1 = array('yo'=>'dream', 'mydear'=> 'not_array');

function is_multi_dimensional($array){
    $flag = 0;
    while(list($k,$value)=each($array)){
        if(is_array($value))
            $flag = 1;
    }
    return $flag;
}
echo is_multi_dimensional($array); // returns 1
echo is_multi_dimensional($array1); // returns 0

1 Comment

This answer is not optimized because it does not conditionally return early.
1

This function will return int number of array dimensions (stolen from here).

function countdim($array)
{
   if (is_array(reset($array))) 
     $return = countdim(reset($array)) + 1;
   else
     $return = 1;
 
   return $return;
}

3 Comments

This will only work for Greg's case. It's not a general solution to the problem where the second dimension could be anywhere in the array
$arr = array("hello", "hi" => "hi there"); $arr[] = &arr; //oops
This answer does not check multiple elements in each level. This answer is very untrustworthy for this asked question.
0

I think this one is classy (props to another user I don't know his username):

static public function isMulti($array)
{
    $result = array_unique(array_map("gettype",$array));

    return count($result) == 1 && array_shift($result) == "array";
}

1 Comment

This is not going to be a performant solution -- array_map() does not allow short circuiting, so the FULL array will be iterated. There are other solutions on this page that are better than this one.
0

In my case. I stuck in vary strange condition.
1st case = array("data"=> "name");
2nd case = array("data"=> array("name"=>"username","fname"=>"fname"));
But if data has array instead of value then sizeof() or count() function not work for this condition. Then i create custom function to check.
If first index of array have value then it return "only value"
But if index have array instead of value then it return "has array"
I use this way

 function is_multi($a) {
        foreach ($a as $v) {
          if (is_array($v)) 
          {
            return "has array";
            break;
          }
          break;
        }
        return 'only value';
    }

Special thanks to Vinko Vrsalovic

1 Comment

This code is not reliable; it only checks the first element. Why break inside of the condition if you are going to break immediately after the condition? Why use any breaks if you are only going to return after breaking? This is just another verbose version of other earlier answers on this page that do not do a great job of evaluating the whole array.
0

Its as simple as

$isMulti = !empty(array_filter($array, function($e) {
                    return is_array($e);
                }));

1 Comment

This is not going to be a performant solution -- array_filter() does not allow short circuiting, so the FULL array will be iterated. There are other solutions on this page that are better than this one. It is needless to call the empty() function when the passed in value is guaranteed to exist. !empty() can be replaced with a function-less type cast (bool).
0
$is_multi_array = array_reduce(array_keys($arr), function ($carry, $key) use ($arr) { return $carry && is_array($arr[$key]); }, true);

Here is a nice one liner. It iterates over every key to check if the value at that key is an array. This will ensure true

1 Comment

This is not going to be a performant solution -- array_reduce() does not allow short circuiting, so the FULL array will be iterated. There are other solutions on this page that are better than this one.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.