Как проверить, является ли массив PHP ассоциативным или последовательным?

PHP рассматривает все массивы как ассоциативные, поэтому встроенных функций нет. Может ли кто-нибудь порекомендовать довольно эффективный способ проверить, содержит ли массив только числовые ключи?

По сути, я хочу различать это:

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

и это:

$assocArray = [
    'fruit1' => 'apple',
    'fruit2' => 'orange',
    'veg1' => 'tomato',
    'veg2' => 'carrot'
];

В вашем коде есть ошибка: помидор - это фрукт.

Olle Härstedt 02.03.2016 17:19

У этого метода есть предостережения, но часто я просто использую if (isset($array[0])), это просто и быстро. Конечно, сначала вы должны убедиться, что массив не пуст, и вы должны иметь некоторые знания о возможном содержимом массива, чтобы метод не смог дать сбой (например, смешанный числовой / ассоциативный или непоследовательный).

Gras Double 12.03.2016 20:58

@ OlleHärstedt Not в соответствии с Высокий суд США. ;-)

MC Emperor 06.03.2020 16:56
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
818
3
270 846
55
Перейти к ответу Данный вопрос помечен как решенный

Ответы 55

Если PHP не имеет для этого встроенных средств, вы не сможете сделать это менее чем за O (n) - перечисляя все ключи и проверяя целочисленный тип. Фактически, вы также хотите убедиться, что нет никаких дыр, поэтому ваш алгоритм может выглядеть так:

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

Но зачем беспокоиться? Предположим, что это массив того типа, который вы ожидаете. В противном случае он просто взорвется вам в лицо - это динамическое программирование для вас! Протестируйте свой код, и все будет хорошо ...

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

Wilco 06.10.2008 11:24

Один дешевый и грязный способ - это проверить так:

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

... вы можете получить ложное срабатывание, если ваш массив выглядит следующим образом:

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

Более тщательным способом может быть проверка ключей:

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

или же

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

+1 для метода isset. Да, это грязно, но это единственный метод, который использует O (1) вместо O (n).

TinkerTank 24.06.2012 21:47

Полный arrayIsAssociative() возвращает правда как для array("a", "b", "c"), так и для array("a", "b"=>"b", "c"), но ложный для array("a") и array(2=>"a").

Pang 23.11.2012 05:50

function is_associative($arr) {
  return (array_merge($arr) !== $arr || count(array_filter($arr, 'is_string', ARRAY_FILTER_USE_KEY)) > 0);
}

implode принимает 2 аргумента, плюс эта функция вернет false для массива, определенного следующим образом: $ x = array ("1" => "b", "0" => "a");

nickf 06.10.2008 11:20

Параметр glue для implode () стал необязательным в PHP 4.3.0. Ваш пример массива - $ x = array ("1" => "b", "0" => "a"); - имеет ассоциативный индекс непоследовательных строк. is_associative () вернет true для этого массива, как и ожидалось.

scronide 06.10.2008 11:56

Мне нравится этот. Первое условное выражение обнаружит ассоциативные массивы, где числовые индексы не являются последовательными в числовом отношении или где первый индекс не равен «0», потому что array_merge будет повторно индексировать ключи численно индексированного (но, возможно, ассоциативного) массива.

DWright 10.11.2010 21:30

-1; при этом используется дополнительная память O(n), когда $arr имеет элементы n, плюс нет объяснения того, что он делает, или исследования двусмысленности заданного вопроса. Он также рассматривает массив, который имеет последовательные числовые ключи и пустая строка в качестве ключа, как неассоциативный, что не поддается никакому разумному определению, которое можно было бы составить между «ассоциативным» и «последовательным» массивами.

Mark Amery 07.01.2016 02:49

@MarkAmery Интересный момент о пустой строке в качестве ключа.

scronide 07.01.2016 03:25
Ответ принят как подходящий

Вы задали два вопроса, которые не совсем эквивалентны:

  • Во-первых, как определить, имеет ли массив только числовые ключи.
  • Во-вторых, как определить, есть ли в массиве числовые ключи последовательный, начиная с 0

Подумайте, какое из этих поведений вам действительно нужно. (Возможно, для ваших целей подойдет любой из них.)

Первый вопрос (просто проверка того, что все клавиши числовые) - хорошо ответил капитан КурО.

Для второго вопроса (проверка того, является ли массив с нулевым индексом и последовательным), вы можете использовать следующую функцию:

function isAssoc(array $arr)
{
    if (array() === $arr) return false;
    return array_keys($arr) !== range(0, count($arr) - 1);
}

var_dump(isAssoc(['a', 'b', 'c'])); // false
var_dump(isAssoc(["0" => 'a', "1" => 'b', "2" => 'c'])); // false
var_dump(isAssoc(["1" => 'a', "0" => 'b', "2" => 'c'])); // true
var_dump(isAssoc(["a" => 'a', "b" => 'b', "c" => 'c'])); // true

Очень элегантное решение. Обратите внимание, что он возвращает ИСТИНА в (неоднозначном) случае пустого массива.

Jonathan Lidbeck 08.01.2016 03:09

Я думаю, что более полезно рассматривать последовательные массивы как частный случай ассоциативных массивов. Таким образом, каждый массив ассоциативен, но только некоторые из них являются последовательными. Следовательно, функция isSequential() будет иметь больше смысла, чем isAssoc(). В такой функции пустой массив должен рассматривается как последовательный. Формула может быть array() === $arr || !isAssoc($arr).

donquixote 21.02.2016 05:03

Я думаю, что это позволило бы избежать большого количества потенциального времени и памяти процессора, если бы можно было проверить, является ли isset ($ arr [0]) ложным, прежде чем извлекать все ключи, поскольку он явно ассоциативен, если массив не пуст, но не имеет элемента в 0 позиция. Поскольку «большинство» реальных ассоциативных массивов имеют строки в качестве ключей, это должно быть хорошей оптимизацией для общего случая такой функции.

OderWat 25.05.2017 02:57

@OderWat - ваша оптимизация должна использовать array_key_exists вместо isset, потому что, если нулевой элемент является нулевым значением, isset вернет false неправильно. Нулевое значение обычно должно быть допустимым значением в таком массиве.

OCDev 03.09.2017 22:55

@MAChitgarha, ваша правка изменила поведение функции без объяснения причин и заставила его противоречить описанию в прозе выше того, что она на самом деле должна делать. Я вернул это.

Mark Amery 01.10.2018 00:14

почему второй корпус уступает false? из-за ключа "0"?

slier 27.02.2019 04:09

Не уверен, что это все еще работает с отрицательными ключами массива: wiki.php.net/rfc/negative_array_index

Jimbolino 15.08.2019 04:05

В этом ответе используется пространство O(n). Хорошее решение должно использовать O(1) IMHO.

Manu Manjunath 23.11.2020 13:00

Если вы ищете только нечисловые клавиши (независимо от порядка), вы можете попробовать

function IsAssociative($array)
{
    return preg_match('/[a-z]/i', implode(array_keys($array)));
}
-1 for missing your apostrophe. Oh, and test with array("@"=>"foo");. And ... preg, В самом деле?
ghoti 19.06.2012 18:03

Еще один способ сделать это.

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;

}

Конечно, это лучшая альтернатива.

<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;

Это приведет к дублированию значений в массиве, что потенциально очень дорого. Намного лучше изучить ключи массива.

meagar 20.01.2011 18:47

Если одно из значений массива не установлено, этот код больше не возвращает допустимый результат (например, unset ($ arr [0]); $ isIndexed = array_values ​​($ arr) === $ arr; // возвращает false.)

AdamJonR 06.04.2011 21:57

Пожалуйста, посмотрите мой ответ ниже, который, хотя и не содержательный, один лайнер на самом деле работает для больших массивов.

podperson 11.06.2012 20:19
-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);
ghoti 19.06.2012 17:57

Я просто использовал ==; Я не думаю, что здесь нужен ===. Но чтобы ответить на вопрос «не установлен, и он не работает»: как только вы отключите первый элемент, это больше не массив с целочисленным индексом, начиная с 0. Итак, IMO это работает.

grantwparks 03.08.2012 01:32

Согласитесь с @grantwparks: разреженный массив не индексируется. Интересно, потому что на самом деле нет способа удалить элемент из середины индексированного массива. PHP в основном объявляет все массивы как ассоциативные, а числовые - это просто версия «придумай для меня ключ».

RickMeasham 14.01.2013 05:01

Единственная проблема, с которой я столкнулся, заключается в том, что === будет тратить время на проверку равенства значений, даже если нас интересуют только ключи. По этой причине я предпочитаю версию $k = array_keys( $arr ); return $k === array_keys( $k );.

Jesse 20.01.2013 11:05

Дополнительное примечание, это не работает с массивами, указанными с помощью цифровых клавиш, которые не в порядке. например $ myArr = array (0 => 'a', 3 => 'b', 4 => 1, 2 => 2, 1 => '3'); Одно из возможных решений - запустить ksort ($ arr) перед выполнением теста.

Scott 06.06.2013 01:58

function isAssoc($arr)
{
    $a = array_keys($arr);
    for($i = 0, $t = count($a); $i < $t; $i++)
    {
        if ($a[$i] != $i)
        {
            return false;
        }
    }
    return true;
}

это предполагает, что массив проиндексирован с 0, что не обязательно верно и даст неправильные результаты для массивов, таких как [10=>'x', 20=>'y'].

Gordon 21.06.2012 17:25

Эта функция возвращает правда как для array("a"=>"b"), так и для array("a","b").

Pang 23.11.2012 06:21

Я просто использую функцию key (). Наблюдать:

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

Таким образом, просто проверив ложь, вы можете определить, является ли массив ассоциативным или нет.

Нет. var_dump((bool)key(array(1=>"foo"))); возвращает истину. -1.

ghoti 19.06.2012 17:54

var_dump((bool)key(array("a"=>"foo"))) возвращает правда; var_dump((bool)key(array(""=>"foo"))) возвращает ложный. Кроме того, как var_dump((bool)key(array("foo","bar"))), так и var_dump((bool)key(array("0"=>"foo","a"=>"bar"))) возвращают ложный.

Pang 23.11.2012 05:55

На самом деле наиболее эффективный способ:

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

Это работает, потому что он сравнивает ключи (которые для последовательного массива всегда 0,1,2 и т. д.) С ключами ключей (которые всегда будут 0,1,2 и т. д.).

Умно, но нехорошо. Почему это «самый эффективный»? Было бы намного удобнее просто сравнить array_keys ($ a) с диапазоном (0, count ($ a)). По моему опыту, самое умное решение редко бывает лучшим. Особенно, когда умение буквально не добавляет ценности очевидной и чистой альтернативе.

Shane H 31.07.2012 05:45

Эта функция возвращает true для array(1=>"a"), но false для array("a"=>"a"). Было бы более значимым, если бы != был заменен !==.

Pang 23.11.2012 05:38

@ Pang, вы правы. Сначала я подумал, что ваш комментарий наверняка ошибочен, но, к моему удивлению, [0] == ['a'] в PHP (начиная с 0 == 'a' и, действительно, 0 == 'banana'). Оператор PHP == безумен.

Mark Amery 02.01.2016 02:59

Это неэффективно, поскольку включает вызов array_keys вместо простой проверки до тех пор, пока вы не найдете непоследовательный целочисленный индекс. Под капотом вы делаете это в любом случае, но вы уже продублировали большой массив.

podperson 22.03.2017 00:50

Я сравниваю разницу между ключами массива и ключами результата array_values ​​() массива, который всегда будет массивом с целочисленными индексами. Если ключи одинаковые, это не ассоциативный массив.

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}

-1; при этом используется дополнительная память O(n), когда $array имеет элементы n, а запись (someboolean) ? false : true вместо !someboolean ужасна и необоснованно многословна.

Mark Amery 07.01.2016 02:54

function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}

Это ответ Только (на момент моего комментария), который может иметь дело со следующим: $ array = array (0 => 'blah', 2 => 'yep', 3 => 'wahey')

Shabbyrobe 03.08.2010 15:01

но array('1'=>'asdf', '2'=>'too') будет рассматриваться как ассоциативный массив, хотя на самом деле это не так (ключи на самом деле являются строкой)

Captain kurO 14.04.2011 11:41

@CaptainkurO Вы имеете в виду числовые. Это ассоциативный массив.

devios1 21.02.2012 20:51

Эта функция возвращает true, если ключи: ноль, целые числа (только положительные), пустая строка или любая комбинация вышеперечисленного, например строка «09». Эта функция не принимает во внимание порядок клавиш. Итак, array(0=>'blah', 2=>'yep', 3=>'wahey'), array(0=>'blah', 2=>'yep', 1=>'wahey') и array('blah', 'yep', 'wahey') ассоциативны в соответствии с этой функцией, а array('a'=>'blah', 'b'=>'yep', 'c'=>'wahey') - нет.

Pang 23.11.2012 05:23

@CaptainkurO вы не правы. «1» и «2» будут сохранены как целые числа. Прочтите процитированную часть ответа squirrel от 11 мая 2011 г. в 19:34. PHP не хранит строковые ключи, которые выглядят в точности как целые числа. Он преобразует их в целые числа.

Buttle Butkus 19.05.2013 08:52

Я использовал как array_keys($obj) !== range(0, count($obj) - 1), так и array_values($arr) !== $arr (которые являются двойниками друг друга, хотя второй дешевле первого), но оба не подходят для очень больших массивов.

Это связано с тем, что array_keys и array_values являются очень дорогостоящими операциями (поскольку они создают совершенно новый массив размером примерно с исходный).

Следующая функция более надежна, чем методы, представленные выше:

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;
}

Также обратите внимание, что если вы не хотите отличать разреженные массивы от ассоциативных массивов, вы можете просто вернуть 'assoc' из обоих блоков if.

Наконец, хотя это может показаться гораздо менее «элегантным», чем множество «решений» на этой странице, на практике это намного эффективнее. Практически любой ассоциативный массив будет обнаружен мгновенно. Тщательно проверяются только индексированные массивы, а описанные выше методы не только полностью проверяют индексированные массивы, но и дублируют их.

Эта функция может обрабатывать:

  • массив с отверстиями в индексе (например, 1,2,4,5,8,10)
  • массив с ключами "0x": например, клавиша «08» является ассоциативной, а клавиша «8» - последовательной.

идея проста: если один из ключей НЕ является целым числом, это ассоциативный массив, в противном случае - последовательный.

function is_asso($a){
    foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
    return FALSE;
}
"если один из ключей НЕ является целым числом, это ассоциативный массив, в противном случае - последовательный" - 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.
Mark Amery 02.01.2016 19:39

Если один из ключей НЕ является целым числом, он ЯВЛЯЕТСЯ ассоциативным по своей природе, однако он является последовательным только в том случае, если ключи идут от 0 - длина (массив) - 1. Однако он ЧИСЛЕННЫЙ, если все ключи только пронумерованы, но могут или может не работать со многими функциями массива, которым требуется последовательный массив. Если вы преобразуете числовой массив с отверстиями в последовательный, запустив на нем array_values ​​(array), то он будет преобразован в последовательный.

geilt 05.09.2018 11:10

Чтобы просто проверить, имеет ли массив нецелочисленные ключи (а не то, индексируется ли массив последовательно или с нулевым индексом):

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

Если есть хотя бы один строковый ключ, $array будет рассматриваться как ассоциативный массив.

Этот метод намного лучше, чем кажется. Если count (filter_array) == count (original_array), то это ассоциированный массив. Если count (filter_array) == 0, то это индексированный массив. Если count (filter_array) <count (original_array), то массив имеет как числовые, так и строковые ключи.

Jamol 31.01.2012 17:31

Способ замедлить. Это выполнит итерацию и применит функцию. Посмотрите ниже более быстрые альтернативы или просто проверьте первый ключ на int.

LeMike 18.01.2014 23:27

Это возвращает false для ["1" => "foo", 2, 3]. Неужели нет способа проверить, был ли ключ изначально определен как строка? Кажется, что PHP все переводит в int в определении массива, если может. Жестокий.

ARW 13.07.2014 18:55

@MikePretzlaw из курс он повторяет; (очевидно) невозможно определить, все ли ключи массива являются целыми числами, не глядя на все ключи в массиве. Я предполагаю, что не повторяющиеся альтернативы, которые мы должны увидеть ниже, - это такие, как $isIndexed = array_values($arr) === $arr;? На что я спрашиваю: как вы думаете, работает array_values()? Как вы думаете, как работает === применительно к массивам? Ответ, конечно, заключается в том, что они также перебирают массив.

Mark Amery 25.12.2015 19:25

@ARW «Кажется, что PHP все переводит в int в определении массива, если может». - да, именно так и происходит. Самый большой WTF в том, что он делает это даже с плавающими; если вы попробуете var_dump([1.2 => 'foo', 1.5 => 'bar']);, вы обнаружите, что получаете массив [1 => 'bar']. Нет никакой возможности узнать оригинальный тип ключа. Да, все это ужасно; Массивы PHP - это, безусловно, худшая часть языка, и большая часть ущерба непоправима и связана с идеей использования единой конструкции для традиционных массивов и традиционных хэш-карт, которая с самого начала была ужасной.

Mark Amery 25.12.2015 19:35

@MarkAmery Вышеупомянутое, хотя и простое, гарантирует 100% обход массива. Это было бы более эффективно, особенно если вы имеете дело с большими массивами, если бы вы проверяли строку или int и выскакивали при первом обнаружении. Например: function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }

Thought 18.02.2016 20:27

@ Thought Ваш код работает очень быстро, но не может обнаружить последовательный массив. Пример array(1 => 'a', 0 => 'b', 2 => 'c') станет false (последовательный массив), тогда как он должен быть true (ассоциативный массив). toolsqa.com/data-structures/array-in-programming Я не уверен, что ключ должен быть в порядке возрастания? (0, 1, ...)

vee 21.05.2019 19:42

@vee - действительно, в самой первой строке ответа говорится, что этот ответ не определяет, есть ли у массива последовательные индексы. Для этого см. Ответ Марка Амери, который использует array_keys.

ToolmakerSteve 15.02.2020 23:21

@ToolmakerSteve Меня упомянули в комментарии Мысль, а не в ответе (Капитан КурО). Это отличается.

vee 17.02.2020 08:57

Может ли это быть решением?

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

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

Эта функция возвращает ложный как для array("a", "b"), так и для array("a", "b" => "B"), поскольку она проверяет только первый ключ. Кстати, is_long - это просто псевдоним is_int.

Pang 24.11.2012 06:20

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

Gershy 30.01.2015 22:58

Это просто неправильно; он смотрит только на первый ключ.

Mark Amery 02.01.2016 19:59

@MarkAmery задан вопрос, как отличить последовательные массивы чисто от ассоциативных массивов чисто. Этот ответ делает именно это и является наиболее эффективным из всех. Наличие неопределенного поведения для массивов смешанный совершенно нормально в контексте вопроса. +1

Tobia 20.07.2016 11:30

@Tobia Я не думаю, что большинство людей согласятся с тем, что вы классифицируете, скажем, [7 => 'foo', 2 => 'bar'] как "смешанный" массив, который является частично, но не "чисто" последовательным. Мне это кажется совершенно неправильным употреблением слов.

Mark Amery 20.07.2016 11:57

@MarkAmery Ваш пример представляет собой последовательный числовой массив? Нет. Это ассоциативный массив (со строковыми ключами)? Нет. Поэтому это выходит за рамки этого ответа, ИМХО. Вы можете подумать о выводе yaml_parse_file(), если хотите (и о обычном способе записи файлов YAML). Вы получаете либо последовательные числовые массивы (если вы начинаете свои разделы с -), либо ассоциативные массивы на основе строк (если вы начинаете свои разделы с name:.) Нет промежуточных.

Tobia 20.07.2016 12:01

Модификация по самому популярному ответу
Это требует немного большей обработки, но более точный.

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

-1; это займет время у O(n²), учитывая последовательный массив размером n. Это будет ужасно неэффективно для достаточно больших массивов.

Mark Amery 02.01.2016 20:08

Многие комментаторы, ответившие на этот вопрос, не понимают, как массивы работают в PHP. Из документация по массиву:

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.

Другими словами, не существует такой вещи, как ключ массива «8», потому что он всегда будет (незаметно) преобразован в целое число 8. Таким образом, попытки различать целые числа и числовые строки не нужны.

Если вам нужен наиболее эффективный способ проверки массива на наличие нецелочисленных ключей без создания копии части массива (например, array_keys ()) или всего его (например, foreach):

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);

Это работает, потому что key () возвращает NULL, когда текущая позиция массива недействительна, и NULL никогда не может быть допустимым ключом (если вы попытаетесь использовать NULL в качестве ключа массива, он будет незаметно преобразован в "").

Это не работает для непоследовательных целочисленных ключей. Попробуйте это с помощью [2 => 'a', 4 => 'b'].

DavidJ 04.09.2012 16:29

@DavidJ, что значит "не работает"? Он успешно определяет, что все ключи являются целыми числами. Вы утверждаете, что массив, подобный тому, который вы опубликовали, не следует рассматривать как «числовой массив»?

coredumperror 16.03.2013 04:29

Неассоциативный массив должен иметь ключи в диапазоне от 0 до count($array)-1 в этом строгом порядке. Предварительная проверка с помощью is_array() может помочь. Добавьте увеличивающуюся переменную, чтобы проверить последовательность клавиш: for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k; На этом сделка рассчитывается.

ofavre 25.06.2013 19:52

Использование foreach вместо явной итерации примерно в два раза быстрее.

ofavre 26.06.2013 13:06

Если вы хотите превратить это в функцию: function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }

Katrina 18.02.2015 20:15

Числовые массивы не обязательно должны иметь ключи от 0 до count($arr)-1. Эти два примера представляют собой идеальные неассоциативные массивы с непоследовательными ключами: $arr = [ 'A', 'B', 'C', 'D' ]; unset( $arr[2] ); или $arr = [ 2 => 'A', 4 => 'B', 9 => 'C', 'D' ];.

Philipp 01.06.2018 12:03

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

Josh from Qaribou 09.07.2019 05:29

Другой вариант, который еще не показан, так как он просто не принимает числовые ключи, но мне очень нравится вариант Грега:

 /* Returns true if $var associative array */  
  function is_associative_array( $array ) {  
    return is_array($array) && !is_numeric(implode('', array_keys($array)));  
  }

Эта функция возвращает ложный для array(2=>'a',3=>'b'), array('a','b'), array("0x"=>'a','f'=>'g'), array("90"=>'a',"17"=>'b'), array(""=>'b',20=>'c').

Pang 23.11.2012 06:12

@Pang: если бы вы могли прочитать: «Он просто не принимает числовые ключи», вы могли бы просто удалить отрицательный голос. Спасибо.

hornetbzz 26.11.2012 20:56

Ваш is_associative_array() возвращает ложный для ассоциативных массивов, таких как array("0x"=>'a','f'=>'g') и array(""=>'b',20=>'c'). Теперь я в замешательстве.

Pang 27.11.2012 05:29

Вот метод, который я использую:

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')) );

Обратите внимание, что это не учитывает особые случаи, такие как:

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

unset($a[1]);

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

Извините, я не могу вам с этим помочь. Он также несколько эффективен для массивов приличного размера, поскольку не создает ненужных копий. Именно эти мелочи делают Python и Ruby намного приятнее для написания ...: P

Лучшая функция для обнаружения ассоциативного массива (хеш-массива)

<?php
function is_assoc($arr) { return (array_values($arr) !== $arr); }
?>

не работает для одноэлементных ассоциативных массивов

Jinu Joseph Daniel 05.07.2012 23:37

Разве это не повторяющийся ответ?

Sharique Abdullah 25.07.2012 11:30

Можешь привести пример, Джину? Я не вижу такого поведения. (Хотя я использую ==, а не ===; я не знаю, почему так много людей используют ===.)

grantwparks 03.08.2012 01:39

По скорости:

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

По памяти:

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

следующий массив: array (02 => 11,1,2,456); показан как не имеющий цифровых ключей с использованием вышеуказанного алгоритма, даже если 02 === 2

Galileo_Galilei 18.11.2015 12:50

Простое и удобное решение, которое проверяет только первый ключ.

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

            break;
        }
    }

    return false;
}

Эта функция возвращает правда как для array("a", "b"), так и для array("a", "b" => "B"), поскольку она проверяет только первый ключ (обратите внимание на return и break).

Pang 24.11.2012 06:25

Я снова столкнулся с этой проблемой несколько дней назад и решил воспользоваться специальным свойством array_merge:

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;
}

Мое решение - получить ключи массива, как показано ниже, и проверить, не является ли ключ целым числом:

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

Неправильно получать array_keys хеш-массива, как показано ниже:

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

выведет:

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

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

Вопрос в том, как проверить, является ли массив последовательный. Массив array(1 => 'foo', 0 => 'bar') не является последовательный, но пройдет ваш тест. Чтобы понять, почему это имеет значение, попробуйте json_encode($array) с последовательными и ассоциативными массивами.

deceze 17.12.2011 09:00

да, я думаю, я очень запутался и застрял с приведенными выше ответами. Который продолжал сравнивать array_keys с диапазоном и думал, что у них будет результат, который будет сравнивать, является ли это хешем или нет. Итак, я отвечаю им, а также тем, кто думает, что array_keys дает значения последовательными. это все. А также имя функции is_hash, поэтому да, оно не говорит вам, является ли оно последовательным или нет

GO.exe 19.12.2011 05:26

<?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);
}

?>

Оба этих примера, набравшие наибольшее количество баллов, некорректно работают с массивами вроде $array = array('foo' => 'bar', 1).

+1 Ваш is_list () - ИМО лучший ответ. Некоторые люди не имеют ни малейшего представления о сложности времени и пространства, а также о встроенной функции и функции сценария PHP ...

e2-e4 16.11.2012 19:00

Это тоже сработает (демонстрация):

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

Обратите внимание, что основная цель этого ответа - сообщить вам о существовании SplFixedArray, а не побуждать вас использовать исключения для такого рода тестов.

Собственно, я оказался в похожей ситуации, пытаясь взять массив и преобразовать его в XML. Имена XML-элементов не могут начинаться с цифр, а найденные мной фрагменты кода некорректно работали с массивами с числовыми индексами.

Details on my particular situation are below

Ответ, предоставленный выше @null (http: // stackoverflow .com / a / 173589/293332), на самом деле был чертовски близок. Я был встревожен тем, что за него проголосовали: те, кто не понимает регулярное выражение, ведут очень разочаровывающую жизнь.

В любом случае, основываясь на его ответе, вот что у меня получилось:

/** 
 * 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 ) ) ) );
}

Дополнительную информацию см. На страницах Последовательности побега PCRE и Синтаксис PCRE.

Моя особая ситуация

Вот пример массива, с которым я имею дело:

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",
    ),
);

Загвоздка в том, что ключ filter является переменным. Например:

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

Зачем мне нужен доц. Проверка массива

Если преобразовываемый мной массив похож на Случай А, я хочу вернуть:

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

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

<?xml version = "1.0" encoding = "UTF-8" standalone = "yes"?>
<GetInventorySummary>
    <Filters>
        <Filter>
            <foo>bar</foo>
            <bar>foo</bar>
        </Filter>
    </Filters>
    <SummaryField>Length</SummaryField>
</GetInventorySummary>

Этот isAssociativeArray() возвращает ложный для array(4=>"four",9=>"nine"), array("002"=>"two","007"=>"james") и array("a", ""=>"empty", "b"), которые явно ассоциативны.

Pang 24.11.2012 06:45

Я думаю, что следующие две функции - лучший способ проверить, является ли массив ассоциативным или числовым. Поскольку «числовой» может означать только цифровые клавиши или только последовательные цифровые клавиши, ниже перечислены две функции, которые проверяют любое условие:

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));
}

Первая функция проверяет, является ли каждый ключ целочисленным значением. Вторая функция проверяет, является ли каждый ключ целочисленным значением, и, кроме того, проверяет, все ли ключи являются последовательными, начиная с $ base, которое по умолчанию равно 0 и, таким образом, может быть опущено, если вам не нужно указывать другое базовое значение. key ($ my_array) возвращает null, если указатель чтения перемещается за конец массива, что завершает цикл for и заставляет оператор после цикла for возвращать значение true, если все ключи были целыми числами. В противном случае цикл завершается преждевременно, поскольку ключ имеет строковый тип, а оператор после цикла for вернет false. Последняя функция дополнительно добавляет единицу к $ base после каждого сравнения, чтобы иметь возможность проверить, имеет ли следующий ключ правильное значение. Строгое сравнение позволяет также проверять, имеет ли ключ целочисленный тип. Часть $ base = (int) $ base в первом разделе цикла for может быть опущена, если $ base опущено или если вы убедитесь, что она вызывается только с использованием целого числа. Но поскольку я не могу быть уверен для всех, я оставил это. В любом случае оператор выполняется только один раз. Думаю, это самые эффективные решения:

  • С точки зрения памяти: без копирования данных или диапазонов ключей. Выполнение array_values ​​или array_keys может показаться короче (меньше кода), но помните, что происходит в фоновом режиме, когда вы делаете этот вызов. Да, здесь больше (видимых) утверждений, чем в некоторых других решениях, но это не то, что имеет значение, не так ли?
  • С точки зрения времени: помимо того факта, что копирование / извлечение данных и / или ключей также требует времени, это решение более эффективно, чем выполнение foreach. Опять же, foreach может показаться некоторым более эффективным, потому что он короче в нотации, но в фоновом режиме foreach также вызывает reset, key и next для выполнения цикла. Но, кроме того, он также вызывает действительный для проверки конечного условия, которого здесь избегают благодаря комбинации с целочисленной проверкой.

Помните, что ключ массива может быть только целым числом или строкой, а строго числовая строка, такая как «1» (но не «01»), будет преобразована в целое число. Именно поэтому проверка целочисленного ключа является единственной необходимой операцией помимо подсчета, если вы хотите, чтобы массив был последовательным. Естественно, если is_indexed_array возвращает false, массив можно рассматривать как ассоциативный. Я говорю «видел», потому что на самом деле они все.

Это лучший ответ. Определение «ассоциативного» или «числового» массива зависит от конкретной ситуации.

Pato 02.05.2013 22:38

Если foreach менее эффективен, чем используемый здесь метод, то, помимо неудобства использования двух разных функций, производительность этого решения лучше, чем у моего (предыдущего). Я подозреваю, что это не так, поскольку foreach рекомендуется как самый быстрый способ пройти через массив.

podperson 13.10.2019 08:19

Как заявлено ОП:

PHP treats all arrays as associative

не совсем разумно (IMHO) писать функцию, которая проверяет, является ли массив ассоциативный. Итак, первым делом: что такое ключ в массиве PHP ?:

The key can either be an integer or a string.

Это означает, что есть 3 возможных случая:

  • Случай 1. все ключи - числовой / целые числа.
  • Случай 2. все ключи - струны.
  • Случай 3. некоторые ключи - струны, некоторые - числовой / целые числа.

Мы можем проверить каждый случай с помощью следующих функций.

Случай 1: все ключи - числовой / целые числа.

Примечание: Эта функция также возвращает правда для пустых массивов.

//! 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);
}

Случай 2: все ключи - струны.

Примечание: Эта функция также возвращает правда для пустых массивов.

//! 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);
}

Случай 3. некоторые ключи - струны, некоторые - числовой / целые числа.

Примечание: Эта функция также возвращает правда для пустых массивов.

//! 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;
}

Это следует из того:

  • Если значение равно не массив, функции все 3 возвращают ложный.
  • Если значение равно пустой массив, функции все 3 возвращают правда
    . (что по определению, как в "пустой набор является подмножеством любого набора А, потому что все его элементы принадлежат А").
  • Если значение равно непустой массив, функция ровно 1 возвращает правда.

Теперь, чтобы массив был «подлинный» массив, к которому мы все привыкли, то есть:

  • Все его ключи - числовой / целые числа.
  • Его ключи - последовательный (т.е. увеличиваются на шаг 1).
  • Его ключи начать с нуля.

Мы можем проверить с помощью следующей функции.

Случай 3а. ключи: числовой / целые числа, последовательный и с нуля.

Примечание: Эта функция также возвращает правда для пустых массивов.

//! 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);
}

Предостережения / подводные камни (или даже более специфические факты о ключах массива в PHP)

Целочисленные ключи

Ключи для этих массивов - целые числа:

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

Строковые ключи

Ключи для этих массивов - струны:

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://stackoverflow.com/q/9246051/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!

Целочисленные ключи, похожие на строки

Если вы думаете, что ключ в array("13" => "b") - это нить, Вы неправы. Из документа здесь:

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.

Например, ключ для этих массивов - целые числа:

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

Но ключ для этих массивов - струны:

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.

Более того, согласно док,

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.

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

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

Хуже того, PHP имеет тенденцию быть багги, если целое число находится рядом с границей 231 = 2 147 483 648 (см. ошибка 51430, ошибка 52899). Например, в моей локальной среде (PHP 5.3.8 на XAMPP 1.7.7 в Windows 7) var_dump(array("2147483647" => "b")) дает

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

но на это живая демонстрация на кодовой панели (PHP 5.2.5) то же выражение дает

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

Таким образом, ключ - это целое число в одной среде, но нить в другой, даже если 2147483647 является действительным подписанным 32-битным целое число.

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

podperson 02.06.2015 18:48

Я удивлен, что вы можете преобразовать «-13» в строку, но не «+13». Думаю, никто бы не стал писать «+13» вместо «13», но это все же несколько странно

Tobias 28.10.2020 17:45

Я думаю, что определение скалярного массива будет зависеть от приложения. То есть для некоторых приложений потребуется более строгое понимание того, что квалифицируется как скалярный массив, а для некоторых приложений потребуется более точное понимание.

Ниже я представляю 3 метода разной строгости.

<?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;
}

Я заметил два популярных подхода к этому вопросу: один с использованием array_values(), а другой с использованием key(). Чтобы узнать, что быстрее, я написал небольшую программу:

$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";

Вывод программы на PHP 5.2 на CentOS выглядит следующим образом:

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

Вывод на PHP 5.3 дал аналогичные результаты. Очевидно, использование array_values() намного быстрее.

плохой тест. Вы не тестировали большие массивы. На моем компьютере, начиная с 10К + элементов, метод №2 работает быстрее. Попробуйте с $arrays = Array( 'Array #1' => range(0, 50000), );

nonsensei 04.07.2016 14:07

Я знаю, что добавлять ответ в эту огромную очередь бессмысленно, но вот удобочитаемое решение O (n), которое не требует дублирования каких-либо значений:

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

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

еще один момент. массив в форме [1,2,null,4] не удастся, но это правильный массив. поэтому я добавил некоторые улучшения в stackoverflow.com/a/25206156/501831 с дополнительной проверкой array_key_exists)

lazycommit 08.08.2014 22:14

-1; isset() - неправильный инструмент, потому что он вернет false, если значение установлено, но null, как указано @lazycommit.

Mark Amery 02.01.2016 19:55

function is_array_assoc($foo) {
    if (is_array($foo)) {
        return (count(array_filter(array_keys($foo), 'is_string')) > 0);
    }
    return false;
}

-1 за полное отсутствие объяснения. Сброс еще одного образца кода на вопрос, на который есть ответы 42, без каких-либо объяснений, почему предпочесть его альтернативам, абсолютно никому не поможет. Кроме того, учитывая неоднозначность вопроса и аргументы, которые бушуют по нему в комментариях, здесь кажется необходимым некоторое объяснение того, как именно вы определяете «ассоциативный» или «последовательный» массив.

Mark Amery 07.01.2016 02:56

Мое решение:

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

array_merge в одном массиве переиндексирует все ключи integer, но не другие. Например:

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

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

Итак, если создается список (неассоциативный массив) ['a', 'b', 'c'], то значение удаляется unset($a[1]), затем вызывается array_merge, список переиндексируется, начиная с 0.

-1; это O(n) в дополнительной используемой памяти (поскольку он создал несколько новых массивов с таким же количеством элементов, как и $array), ответ не касается неоднозначности заданного вопроса и не объясняет, как именно он определяет список / неассоциативный массив, и даже если ни один из этих пунктов не был правдой, неясно, добавляет ли это какую-либо ценность по сравнению с другими уже опубликованными ответами.

Mark Amery 07.01.2016 02:46

Еще один пост от источник. Подходит для кодировки json_encodebson_encode). Так что есть соответствие массива javascript.

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__)
        );
    }
}

Почему isset и array_key_exists? разве последнего не хватит?

mcfedr 01.07.2015 00:33

@mcfedr да, будет - проверка isset() здесь полностью избыточна.

Mark Amery 02.01.2016 19:58

@mcfedr, @ mark-amery по соображениям производительности. isset() быстрее, чем array_key_exists(). см. ilia.ws/archives/…

lazycommit 29.01.2016 10:58

@lazycommit Это будет зависеть от вашего массива, а затем от того, лучше ли он с или без, не то, что он, вероятно, будет иметь массив с большим количеством null, но тогда это также маловероятно, что у вас достаточно большой массив, чтобы была заметная разница в производительности используя обе проверки

mcfedr 29.01.2016 11:25

@mcfedr согласен. плохой контроль структуры данных означает чистый дизайн и плохой запах кода. Итак, тема вся тема :)

lazycommit 12.05.2016 16:22

Это правда, что весь вопрос основан на плохо спроектированном коде.

mcfedr 12.05.2016 18:19

если вам нужно проверить, подходит ли он json_encode, вы можете просто проверить первый символ строки, возвращенный json_encode($your_arr) - будь то [ или { ;-)

pilat 29.03.2017 23:07

Используя расширение рентгеновский снимок PHP

Вы можете сделать это очень быстро (примерно в 30+ раз быстрее в PHP 5.6):

if (array_is_indexed($array)) {  }

Или же:

if (array_is_assoc($array)) {  }

Один из способов приблизиться к этому - использовать json_encode, у которого уже есть собственный внутренний метод различения между ассоциативным массивом и индексированным массивом для вывода правильного JSON.

Вы можете сделать это, проверив, является ли первый символ, возвращаемый после кодирования, { (ассоциативный массив) или [ (индексированный массив).

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}

На мой взгляд, ksort () не нужен. Это решение работает, но оно должно проверить, является ли $ arr нулевым и если json_encode не работает, поэтому попробуйте / поймать. + это не совсем оптимально, если $ arr большой.

lucbonnin 12.10.2018 10:36

function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}

Быстро, лаконично и эффективно с точки зрения памяти. Никаких дорогостоящих сравнений, вызовов функций или копирования массивов.

ответы уже даны, но слишком много дезинформации о производительности. Я написал этот небольшой тестовый скрипт, который показывает, что метод foreach самый быстрый.

Отказ от ответственности: следующие методы были скопированы из других ответов

<?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";
}

полученные результаты:

==== 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

Улучшение от Марка Амери

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);
}

Это проверяет, существует ли переменная, является ли это массивом, не является ли это пустым массивом и не являются ли ключи последовательными, начиная с 0.

Чтобы узнать, ассоциативен ли массив

if (isAssoc($array)) ...

Чтобы узнать, числовой ли он

if (!isAssoc($array)) ...

Подождите, что, где я это сделал? Или вы хотели сказать «Улучшение на, Марк Эмери», как улучшение принятого ответа, приписываемого мне? Имейте в виду, что в последнем случае этот ответ был написан не мной - мои правки просто привели к тому, что алгоритм атрибуции авторства для сообщений Community Wiki поместил на нем мое имя.

Mark Amery 21.07.2016 11:10

Простым способом вы можете проверить, является ли массив ассоциативным или нет, с помощью следующих шагов

  1. преобразовать все ключи массива в один массив с помощью array_keys()
  2. отфильтровать нечисловой ключ из массива с помощью array_filter() и is_numeric()
  3. сравнить количество элементов в фильтруемом массиве и фактическом массиве. Если количество элементов не равно в обоих массивах, то это ассоциативный массив.

Функция для вышеуказанного шага указана ниже.

 function isAssociative(array $array)
    {
        return count(array_filter(array_keys($array), function($v){return is_numeric($v);})) !== count($array));
    }

Уже есть много ответов, но вот метод, на который опирается Laravel в своем классе Arr:

/**
 * 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;
}

Источник: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php

@Casey array_keys($keys) вернет последовательный массив чисел (0 ... X), который имеет ту же длину, что и исходный массив. Например array_keys(["a", "b", "c"]) = [0, 1, 2];array_keys([0, 1, 2]) = [0, 1, 2] (это последовательный массив, потому что [0, 1, 2] !== [0, 1, 2]). Другой пример: array_keys(["a" => 5, "b" => 7, "c" => 10]) = ["a", "b", "c"];array_keys(["a", "b", "c"]) = [0, 1, 2] (это ассоциативный массив, потому что ["a", "b", "c"] !== [0, 1, 2]). Надеюсь, это ясно (сложно подробно объяснить в комментарии, по крайней мере, для меня)

valepu 04.09.2018 16:46

Этот алгоритм безумный, простой, понятный.

Benyi 10.10.2018 09:59

Это не сработает, если у вас есть последовательный массив ассоциативных строк.

lucbonnin 12.10.2018 08:01

Проверка наличия у массива всех связанных ключей. При использовании 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

Почему? Функция get_object_vars возвращает только свойства доступный (подробнее о том, что происходит при преобразовании array в objectздесь). Тогда просто логично: если количество элементов базового массива равно количество доступных свойств объекта - все ключи связаны.

Несколько тестов:

$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

И т.п.

Это не сработает. Доказательство eval.in/859508 $ asocArray - это массив с двумя массивами. Верните истину. Другие доказательства для других exaqmple также не работают, как ваш пример latets eval.in/859507 возвращает true

abkrim 11.09.2017 18:55

После некоторого локального тестирования, отладки, проверки компилятора, профилирования и злоупотребления 3v4l.org для тестирования других версий (да, я получил предупреждение остановиться) и сравнивая со всеми вариантами, которые я мог найти ...

Я даю вам органически полученную функцию тестирования ассоциативного массива лучший-средний-худший сценарий, которая имеет худший примерно так же или лучше, чем все другие сценарии среднего случая.

/**
 * 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;
}

Из 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";
}

Это моя функция -

public function is_assoc_array($array){

    if (is_array($array) !== true){
        return false;
    }else{

        $check = json_decode(json_encode($array));

        if (is_object($check) === true){
            return true;
        }else{
            return false;
        }

    }

}

Некоторые примеры

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

В одном из ответов было аналогичное решение от @ devios1, но это был просто еще один способ использования встроенных функций PHP, связанных с json. Я не проверял, насколько это решение демонстрирует производительность по сравнению с другими решениями, опубликованными здесь. Но это, безусловно, помогло мне решить эту проблему. Надеюсь это поможет.

Или вы можете просто использовать это:

Arr::isAssoc($array)

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

Arr:isAssoc($array, true)

чтобы проверить, содержит ли массив строго последовательный (содержит автоматически сгенерированные ключи int от 0 до п-1)

с использованием библиотеки это.

Я придумал следующий метод:

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

* Обратите внимание, что пустой массив не считается последовательным массивом, но я думаю, что это нормально, поскольку пустые массивы похожи на 0 - не имеет значения, плюс или минус, он пуст.

Вот преимущества этого метода по сравнению с некоторыми из перечисленных выше:

  • Это не связано с копированием массивов (кто-то упомянул в этом суть https://gist.github.com/Thinkscape/1965669, что array_values не предполагает копирование - что! ?? Безусловно, как будет видно ниже.)
  • Это быстрее для больших массивов и в то же время более дружественно к памяти

Я использовал тест, любезно предоставленный Артур Бодера, где я изменил один из массивов на 1M элементов (array_fill(0, 1000000, uniqid()), // big numeric array).

Вот результаты для 100 итераций:

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

* Методы упорядочены по потреблению памяти.

** Я использовал echo " Total memory: " . number_format(memory_get_peak_usage()/1024/1024, 2) . " MB\n"; для отображения использования памяти

если у вас /1024, то это МиБ (Мебибайт), если у вас /1000, то это Мб (мегабайт). Mega === 1000000, в разработке программного обеспечения и в физике, на Луне и на Земле, а также внутри вашего компьютера. Мега никогда не бывает 1024 * 1024. И Кило всегда 1000, а не 1024.

Daniel W. 15.03.2019 19:33

вау @DanFromGermany, спасибо за невероятно полезный комментарий! Это хорошо знать. PS. кстати на самом деле Мега у меня на компьютере ровно 1024 * 1024, он нестандартный :)

Slayer Birden 16.03.2019 20:58

/*
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;
}

• Без обратного вызова это примерно на 30% быстрее, чем текущий лидирующий ответ, и, возможно, более эффективное использование памяти.

• Просто отрицайте ответ, чтобы знать, следует ли считать массив ассоциативным.

Многие решения здесь элегантны и красивы, но плохо масштабируются и требуют интенсивного использования памяти или процессора. Большинство из них создают в памяти 2 новые точки данных с помощью этого решения с обеих сторон сравнения. Чем больше массив, тем сложнее и дольше используются процесс и память, и вы теряете преимущество оценки короткого замыкания. Я провел небольшое тестирование с несколькими разными идеями. Попытка избежать array_key_exists, поскольку это дорого, а также избежать создания новых больших наборов данных для сравнения. Я считаю, что это простой способ определить, является ли массив последовательным.

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;
}

Вы запускаете один подсчет в основном массиве и сохраняете одно целое число. Затем вы просматриваете массив и проверяете точное совпадение при повторении счетчика. У вас должно быть от 1 до счета. Если это не удается, происходит короткое замыкание, что дает вам повышение производительности, когда оно ложно.

Первоначально я делал это с помощью цикла for и проверки isset ($ arr [$ i]), но это не обнаружит нулевые ключи, для которых требуется array_key_exists, и, как мы знаем, это худшая функция для скорости.

Постоянное обновление переменных через foreach для проверки вместе с итератором, никогда не превышающим свой целочисленный размер, позволяет PHP использовать его встроенные функции оптимизации памяти, кеширования и сборки мусора, чтобы поддерживать очень низкое использование ресурсов.

Кроме того, я утверждаю, что использование array_keys в foreach глупо, когда вы можете просто запустить $ key => $ value и проверить ключ. Зачем создавать новую точку данных? Как только вы абстрагируете ключи массива, вы сразу же потребляете больше памяти.

Этот вопрос на самом деле бесполезен, когда дело доходит до массива php, потому что с природой php массив не должен быть полностью ассоциативным или индексируемым, он может быть комбинацией обоих, способ, которым пользователь определил и присвоил значение массиву, может быть сочетание того и другого. см. пример ниже

$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];
}

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

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;
    }
}

вы можете использовать его как обычную функцию

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

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

$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

}

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

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

меньше кода, но это действительно интенсивный процесс и действительно ненужная работа.

Иногда можно обойтись только проверкой того, равен ли ключ первого массива нулю.

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

, или, более быстрая, но более подробная версия:

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

Большинство ответов имеют неоптимальную временную / пространственную сложность или меняют семантику. Итак, вот еще один ответ с решениями самый быстрый и наиболее функционально правильный:

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;
}

Этот ответ имеет следующие преимущества перед другими ответами:

  1. Пространственная сложность O(1) (многие ответы здесь используют пространство O(n)!)
  2. Не применяет равенство ключей (что является нежелательной и дорогостоящей операцией)
  3. Считает входной массив неизменяемым (во многих ответах копия неявно создается путем применения изменяющих функций)
  4. Использует функцию array_key_exists вместо isset (помните, isset дополнительно проверяет "не является нулем", тем самым изменяя семантику)
  5. В худшем случае временная сложность - O(n) (многие ответы здесь имеют временную сложность в лучшем случае O(n))

Я удивлен, что никто не упомянул array_key_first()

Для ваших тестовых случаев:

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

тогда как

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

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

Подробнее об этой функции здесь.

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

Tomasz Kowalczyk 28.09.2020 15:23

Вот еще одна простая, но мощная логика (которая также используется отличным фреймворком Laravel во внутреннем механизме)

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

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

Спасибо! Я использую Laravel, поэтому могу просто использовать родныеArr::isAssoc

Aryeh Beitz 08.03.2021 09:54

Абсолютно ..

dipenparmar12 08.03.2021 11:45

Другие вопросы по теме