Проверка, многомерный массив или нет?

140
  1. Каков наиболее эффективный способ проверить, является ли массив плоским массивом примитивных значений или это многомерный массив ?
  2. Есть ли способ сделать это, не перебирая массив и не выполняя is_array()каждый из его элементов?
Wilco
источник
9
Стоит отметить, что в PHP нет настоящих многомерных массивов - есть только простые ассоциативные массивы значений. Итак, ваш вопрос действительно спрашивает: «Есть ли в моем массиве нескалярное значение»?
gahooa
21
На самом деле ... Я не думаю, что на это стоит вообще указывать.
Joe

Ответы:

137

Короткий ответ - нет, вы не можете этого сделать, по крайней мере, неявно зациклившись, если «второе измерение» может быть где угодно. Если он должен быть в первом элементе, вы просто сделаете

is_array($arr[0]);

Но наиболее эффективный общий способ, который я мог найти, - это использовать цикл foreach в массиве, сокращая замыкание всякий раз, когда обнаруживается попадание (по крайней мере, неявный цикл лучше, чем прямой 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

Неявный цикл, но мы не можем замкнуть его, как только будет найдено совпадение ...

$ 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)
Винко Врсалович
источник
3
Хорошо, с оговоркой, что я считаю, что ваша строка фильтрации должна иметь array_map ("is_array", $ a), а не использовать is_array в качестве голого слова.
Мэтью Шарли,
Хороший улов, который ускорил is_multi, но все еще недостаточно хорош, чтобы соответствовать foreach
Винко Врсалович
2
Стоит отметить, что, как написано, multi_3 будет работать только с неассоциативными массивами с отсчетом от нуля без пробелов в индексах, что означает, что он не будет правильно идентифицировать ни один из этих примеров как многомерный.
Cragmonkey
В функции is_multi()оптимизируйте код, выполнивreturn count($rv)>0
Xorifelse
is_array (array_values ​​($ arr) [0]) как обходной путь для настраиваемых ключей.
Витор Родригес
196

Дважды используйте count (); один раз в режиме по умолчанию и один раз в рекурсивном режиме. Если значения совпадают, массив не является многомерным, так как многомерный массив будет иметь более высокое рекурсивное количество.

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

Второе значение этой опции modeбыло добавлено в PHP 4.2.0. Из документации PHP :

Если необязательный параметр режима установлен в COUNT_RECURSIVE (или 1), count () будет рекурсивно подсчитывать массив. Это особенно полезно для подсчета всех элементов многомерного массива. count () не обнаруживает бесконечную рекурсию.

Однако этот метод не обнаруживает array(array()).

Сообщество
источник
2
Как уже отмечалось, это не работает для элементов с пустыми массивами
Артур
30

Для PHP 4.2.0 или новее:

function is_multi($array) {
    return (count($array) != count($array, 1));
}
скронид
источник
Не работает array(array())или array(array(), array())как. Как правило, если внутренний массив пуст, рекурсивный счетчик правильно добавит для него 0, что приведет к совпадению с обычным счетчиком.
Fanis Hatzidakis
13

Я думаю, что это наиболее простой и современный способ:

function is_multidimensional(array $array) {
    return count($array) !== count($array, COUNT_RECURSIVE);
}
Андреас
источник
9

Вы можете просто выполнить это:

if (count($myarray) !== count($myarray, COUNT_RECURSIVE)) return true;
else return false;

Если необязательный параметр режима установлен в COUNT_RECURSIVE(или 1), count () будет рекурсивно подсчитывать массив. Это особенно полезно для подсчета всех элементов многомерного массива.

Если он такой же, значит, подуровней нигде нет. Легко и быстро!

Pian0_M4n
источник
Спасибо ... полезно. Я хотел проверить, существует ли подуровень в моем массиве, я использовалif(count($tasks_by_date) !== count($tasks_by_date, 1))
Майк Барвик
Круто. COUNT_RECURSIVE или 1 то же самое для count ()
Pian0_M4n
Абсолютно. Мне просто нравится меньше беспорядка, и !==раньше я видел, существует ли подуровень. Для теорий, которые могут искать что-то подобное ... и т. Д.
Майк Барвик,
То, что у вас было, не вернулось для меня ... Мне нужно было добавить!==
Майк Барвик
С пустым массивом, имеет сбой
Уоллес Макстерс
7

Вы можете проверить is_array()первый элемент при условии, что если первый элемент массива является массивом, то и остальные тоже.

Грег Хьюгилл
источник
На самом деле это хороший момент. В моем конкретном случае это ситуация «или / или», поскольку я контролирую создание исходного массива. Я оставлю вопрос пока открытым на случай, если есть решение, которое может работать в более общем плане.
Wilco
5
Как это:if( is_array(current($arr)) ) { // is multidimensional }
Jonas Äppelgran
4

Все отличные ответы ... вот мои три строчки, которые я всегда использую

function isMultiArray($a){
    foreach($a as $v) if(is_array($v)) return TRUE;
    return FALSE;
}
Джо
источник
2

Эта функция вернет целое число измерений массива (украденных отсюда ).

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

   return $return;
}

источник
Это сработает только в случае Грега. Это не общее решение проблемы, когда второе измерение может быть где угодно в массиве,
Винко Врсалович
$ arr = array ("привет", "привет" => "привет"); $ arr [] = & arr; // упс
Tyzoid 08
2

Я думаю, вы обнаружите, что эта функция - самый простой, эффективный и быстрый способ.

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

Проверить это можно так:

$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';
RoboTamer
источник
если вы собираетесь использовать одну строку, по крайней мере, все; foreach($a as $v) is_array($v) ? return TRUE : return FALSE;
Роберт Паундер,
@RobertPounder или дажеforeach($a as $v) return is_array($v) ? true : false;
Яссин Седрани
2

После PHP 7 вы могли просто сделать:

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

источник
1

Вы также можете выполнить простую проверку, например:

$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

Попробуйте следующее

if (count($arrayList) != count($arrayList, COUNT_RECURSIVE)) 
{
  echo 'arrayList is multidimensional';

}else{

  echo 'arrayList is no multidimensional';
}
Аршид К.В.
источник
1

Даже это работает

is_array(current($array));

Если false - это одномерный массив, если true - многомерный массив.

current предоставит вам первый элемент вашего массива и проверит, является ли первый элемент массивом или нет, с помощью функции is_array .

Приянк
источник
Это будет ненадежно, если вы хотите убедиться, что любой другой элемент также не вложен.
vanamerongen
1

Не используйте COUNT_RECURSIVE

нажмите на этот сайт, чтобы узнать почему

используйте rsort, а затем используйте isset

function is_multi_array( $arr ) {
rsort( $arr );
return isset( $arr[0] ) && is_array( $arr[0] );
}
//Usage
var_dump( is_multi_array( $some_array ) );
hendra1
источник
$ arr [0] не может быть массивом, но $ arr [1] может быть массивом
Супун Пранит
1

В моем случае. Я попал в очень странное состояние.
1-й случай = array("data"=> "name");
2-й случай = array("data"=> array("name"=>"username","fname"=>"fname"));
Но если dataвместо значения есть массив, тогда функция sizeof () или count () не работает для этого условия. Затем я создаю настраиваемую функцию для проверки.
Если первый индекс массива имеет значение, он возвращает «только значение».
Но если индекс имеет массив вместо значения, он возвращает «имеет массив».
Я использую этот способ

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

Особая благодарность Винко Врсаловичу

Darkcoder
источник
0

Я думаю, что это классно (реквизит для другого пользователя, я не знаю его имени пользователя):

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

    return count($result) == 1 && array_shift($result) == "array";
}
Альфонсо Фернандес-Окампо
источник
0

Все вышеперечисленные методы слишком сложны для быстрого развертывания. Если массив плоский, тестирование первого элемента должно вернуть примитив, например int, string и т. Д. Если массив многомерный, он должен вернуть массив. Кроме того, вы можете использовать этот один лайнер быстро и аккуратно.

echo is_array(array_shift($myArray));

если это вернет истину, массив является многомерным. Остальное плоское. Следует отметить, что массивы очень редко имеют разные размеры, например, если вы генерируете данные из модели, она всегда будет иметь один и тот же тип многомерной или плоской структуры, по которой можно обходить циклы. петли машинные Если это не так, то вы создали его вручную, что означает, что вы знаете, где все будет находиться, и он просто работает без необходимости писать алгоритм цикла. введите описание изображения здесь

Нельсон Эмека Амейо
источник
Этот метод находит многомерные массивы, только если первый элемент является массивом.
Cragmonkey
Будьте осторожны с использованием array_shift(), так как он удаляет первый элемент, а также сбрасывает цифровые клавиши! Лучше использовать, current()если все еще хочется однострочника.
Марчелло Мёнкемейер
0

В дополнение к предыдущим ответам и в зависимости от схемы массива, который вы хотите проверить:

function is_multi_array($array=[],$mode='every_key'){

    $result = false;

    if(is_array($array)){

        if($mode=='first_key_only'){

            if(is_array(array_shift($array))){

                $result = true;
            }
        }
        elseif($mode=='every_key'){

            $result = true;

            foreach($array as $key => $value){

                if(!is_array($value)){

                    $result = false;
                    break;
                }
            }
        }
        elseif($mode=='at_least_one_key'){

            if(count($array)!==count($array, COUNT_RECURSIVE)){

                $result = true; 
            }
        }
    }

    return $result;
}
РафаСаши
источник
0

Это так просто, как

$isMulti = !empty(array_filter($array, function($e) {
                    return is_array($e);
                }));
Мохд Абдул Муджиб
источник
0
$is_multi_array = array_reduce(array_keys($arr), function ($carry, $key) use ($arr) { return $carry && is_array($arr[$key]); }, true);

Вот хороший лайнер. Он перебирает каждый ключ, чтобы проверить, является ли значение этого ключа массивом. Это обеспечит истинное

Dorpo
источник
-1
if($array[0]){
//enter your code 
}
rthcupid
источник
Хотя бы использовать if (isset($array[0])) { }. Если вы уверены, что индексы массива начинаются с 0
Aistis
Многомерный массив - это массив, содержащий один или несколько массивов. Это только проверяет, содержит ли он элемент с нулевым ключом.
Cragmonkey
-1
if ( array_key_exists(0,$array) ) {

// multidimensional array

}  else {

// not a multidimensional array

}

* только для массивов с числовым индексом

Судхин Бабу
источник
Многомерный массив - это массив, содержащий один или несколько массивов. Это только проверяет, содержит ли он элемент с нулевым ключом.
Cragmonkey,
-1

Собственная функция print_r возвращает удобочитаемую строку. Просто посчитайте экземпляры «Массив».

пытаться...

substr_count(print_r([...array...], true), 'Array') > 1;

$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)));
$d = array(array());
$e = array(1, array());
$f = array(array(), array());
$g = array("hello", "hi" => "hi there");
$h[] = $g;

var_dump(substr_count(print_r($a, true), 'Array') > 1);
...

//a: bool(true)
//b: bool(false)
//c: bool(true)
//d: bool(true)
//e: bool(true)
//f: bool(true)
//g: bool(false)
//h: bool(true)

На моем ящике "is_multi занял 0,83681297302246 секунд в 500000 раз"

Предоставлено: Руах ха-Кодеш

Гонщик X
источник
-2
function isMultiArray(array $value)
{
    return is_array(reset($value));
}
джонатан
источник
Это только проверяет, является ли ПЕРВЫЙ элемент многомерным.
Cragmonkey
-3
is_array($arr[key($arr)]); 

Никаких петель, просто и понятно.

Работает также с ассоциированными массивами, а не только с числовыми массивами, которые не могут содержать 0 (как в предыдущем примере, вы получите предупреждение, если массив не имеет 0).

Карлос
источник
По ключе не обнаруживается массив, необходимо проверить значение
RoboTamer