PHP обрабатывает все массивы как ассоциативные, поэтому встроенных функций нет. Кто-нибудь может порекомендовать довольно эффективный способ проверить, содержит ли массив только числовые ключи?
В принципе, я хочу иметь возможность различать это:
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
и это:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
if (isset($array[0]))
, что просто и быстро. Конечно, вы должны сначала убедиться, что массив не пустой, и у вас должны быть некоторые знания о возможном содержимом массива, чтобы метод не мог завершиться с ошибкой (например, смешанный числовой / ассоциативный или непоследовательный).Ответы:
Вы задали два вопроса, которые не совсем эквивалентны:
Подумайте, какое из этих поведений вам действительно нужно. (Может быть, что либо подойдет для ваших целей.)
На первый вопрос (просто проверяя, что все ключи цифровые) хорошо ответил Captain kurO .
Для второго вопроса (проверка, является ли массив нулевым и последовательным), вы можете использовать следующую функцию:
источник
isSequential()
будет иметь больше смысла, чемisAssoc()
. В такой функции пустой массив должен рассматриваться как последовательный. Формула может бытьarray() === $arr || !isAssoc($arr)
.array_key_exists
вместо того, чтобы,isset
если нулевой элемент является нулевым значением, isset вернет false неправильно. Нулевое значение обычно должно быть допустимым значением в таком массиве.Чтобы просто проверить, есть ли в массиве нецелочисленные ключи (не является ли массив последовательно индексированным или нулевым):
Если есть хотя бы один строковый ключ,
$array
будет рассматриваться как ассоциативный массив.источник
$isIndexed = array_values($arr) === $arr;
? На что я спрашиваю: как вы думаете,array_values()
работает? Как вы думаете,===
применительно к массивам работает? Ответ, конечно, в том, что они также перебирают массив.var_dump([1.2 => 'foo', 1.5 => 'bar']);
вы обнаружите, что вы получите массив[1 => 'bar']
. Нет никакого способа узнать оригинальный тип ключа. Да, все это ужасно; Массивы PHP на сегодняшний день являются худшей частью языка, и большая часть ущерба является непоправимой и обусловлена идеей использования единой конструкции для традиционных массивов и традиционных хеш-карт с самого начала.function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
array(1 => 'a', 0 => 'b', 2 => 'c')
станетfalse
(последовательный массив), а должно бытьtrue
(ассоциативный массив). toolsqa.com/data-structures/array-in-programming Я не уверен, что ключ должен быть в порядке возрастания? (0, 1, ...)Конечно, это лучшая альтернатива.
источник
===
будем тратить время на проверку, равны ли значения, хотя нас интересуют только ключи. По этой причине я предпочитаю$k = array_keys( $arr ); return $k === array_keys( $k );
версию.Многие комментаторы в этом вопросе не понимают, как работают массивы в PHP. Из документации массива :
Другими словами, не существует такой вещи, как ключ массива «8», потому что он всегда будет (молча) преобразовываться в целое число 8. Поэтому пытаться различать целые и числовые строки не нужно.
Если вы хотите наиболее эффективный способ проверить массив на наличие нецелочисленных ключей без создания копии части массива (как это делает array_keys ()) или всего этого (как и foreach):
Это работает, потому что key () возвращает NULL, когда текущая позиция массива недопустима, и NULL никогда не может быть допустимым ключом (если вы попытаетесь использовать NULL в качестве ключа массива, он будет автоматически преобразован в "").
источник
0
доcount($array)-1
в этом строгом порядке. Предварительная проверка сis_array()
может помочь. Добавьте увеличивающуюся переменную, чтобы проверить последовательность клавиш:for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k;
это урегулирует сделку.foreach
вместо явной итерации примерно в два раза быстрее.function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
Как указано в ОП :
не совсем разумно (ИМХО) писать функцию, которая проверяет, является ли массив ассоциативным . Итак, первым делом: что является ключом в массиве PHP ?
Это означает, что есть 3 возможных случая:
Мы можем проверить каждый случай с помощью следующих функций.
Случай 1: все ключи числовые / целые .
Примечание : эта функция возвращает true и для пустых массивов.
Случай 2: все ключи являются строками .
Примечание : эта функция возвращает true и для пустых массивов.
Случай 3. некоторые ключи являются строками , некоторые ключи являются числовыми / целыми числами .
Примечание : эта функция возвращает true и для пустых массивов.
Это следует из того:
(что по определению, как в « пустом множестве, является подмножеством любого множества A, поскольку все его элементы принадлежат A »).
Теперь, чтобы массив был «подлинным» массивом, к которому мы все привыкли, это означает:
Мы можем проверить с помощью следующей функции.
Дело 3а. ключи числовые / целые , последовательные и начинающиеся с нуля .
Примечание : эта функция возвращает true и для пустых массивов.
Предостережения / Подводные камни (или, еще более странные факты о ключах массива в PHP)
Целочисленные ключи
Ключи для этих массивов являются целыми числами :
Струнные ключи
Ключи для этих массивов являются строками :
Целочисленные ключи, которые выглядят как строки
Если вы думаете, что ключ
array("13" => "b")
является строкой , вы ошибаетесь . Из документа здесь :Например, ключ для этих массивов - целые числа :
Но ключом для этих массивов являются строки :
Более того, согласно документу ,
Таким образом, ключ для этого массива может быть или не быть целым числом - это зависит от вашей платформы.
Хуже того, PHP склонен к ошибкам, если целое число находится рядом с границей 2 31 = 2 147 483 648 (см. Ошибку 51430 , ошибку 52899 ). Например, в моей локальной среде (PHP 5.3.8 на XAMPP 1.7.7 на Windows 7),
var_dump(array("2147483647" => "b"))
даетно в этом живом демо на кодовой панели (PHP 5.2.5) то же выражение дает
Таким образом, ключ - это целое число в одной среде, но строка в другой, даже если
2147483647
это действительное 32-разрядное целое число со знаком .источник
Скорость-накрест:
Память-накрест:
источник
источник
array('1'=>'asdf', '2'=>'too')
будет рассматриваться как ассоциативный массив, хотя на самом деле это не так (ключи на самом деле строковые)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')
нет.На самом деле самый эффективный способ это:
Это работает, потому что сравнивает ключи (которые для последовательного массива всегда 0,1,2 и т. Д.) С ключами ключей (которые всегда будут 0,1,2 и т. Д.).
источник
true
для,array(1=>"a")
ноfalse
дляarray("a"=>"a")
. Было бы более значимым, если!=
заменить на!==
.[0] == ['a']
в PHP (поскольку0 == 'a'
, и действительно0 == 'banana'
).==
Оператор PHP безумен.Я использовал оба
array_keys($obj) !== range(0, count($obj) - 1)
иarray_values($arr) !== $arr
(которые являются двойными по отношению друг к другу, хотя второе дешевле первого), но оба не подходят для очень больших массивов.Это происходит потому , что
array_keys
иarray_values
оба очень дорогостоящие операции (так как они создают совершенно новый массив размером примерно с оригиналом).Следующая функция более надежна, чем методы, представленные выше:
Также обратите внимание, что если вы не хотите отличать разреженные массивы от ассоциативных, вы можете просто вернуться
'assoc'
из обоихif
блоков.Наконец, хотя это может показаться гораздо менее «изящным», чем многие «решения» на этой странице, на практике это гораздо более эффективно. Почти любой ассоциативный массив будет обнаружен мгновенно. Только индексированные массивы будут проверяться исчерпывающе, а описанные выше методы не только тщательно проверяют индексированные массивы, но и дублируют их.
источник
Я думаю, что следующие две функции - лучший способ проверить, является ли массив ассоциативным или числовым. Поскольку «числовой» может означать только цифровые клавиши или только последовательные цифровые клавиши, ниже перечислены две функции, которые проверяют любое условие:
Первая функция проверяет, является ли каждая клавиша целочисленным значением. Вторая функция проверяет, является ли каждая клавиша целочисленным значением, и дополнительно проверяет, все ли ключи последовательны, начиная с $ base, который по умолчанию равен 0 и, следовательно, может быть опущен, если вам не нужно указывать другое базовое значение. key ($ my_array) возвращает значение null, если указатель чтения перемещается за конец массива, что и завершает цикл for, а оператор после цикла for возвращает true, если все ключи были целыми числами. Если нет, цикл преждевременно завершается, потому что ключ имеет тип string, а оператор после цикла for возвращает false. Последняя функция дополнительно добавляет единицу к $ base после каждого сравнения, чтобы иметь возможность проверить, имеет ли следующий ключ правильное значение. Строгое сравнение позволяет также проверить, имеет ли ключ тип integer. Часть $ base = (int) $ base в первом разделе цикла for может быть пропущена, если $ base пропущен или если вы убедитесь, что он вызывается только с помощью целого числа. Но так как я не могу быть уверен во всех, я оставил это. В любом случае, заявление выполняется только один раз. Я думаю, что это самые эффективные решения:
Помните, что ключ массива может быть только целым числом или строкой, и строго числовая строка, такая как «1» (но не «01»), будет преобразована в целое число. Что делает проверку целочисленного ключа единственной необходимой операцией, кроме подсчета, если вы хотите, чтобы массив был последовательным. Естественно, если is_indexed_array возвращает false, массив можно рассматривать как ассоциативный. Я говорю «видел», потому что на самом деле они все есть.
источник
Эта функция может обрабатывать:
Идея проста: если один из ключей НЕ является целым числом, это ассоциативный массив, в противном случае он является последовательным.
источник
Я заметил два популярных подхода к этому вопросу: один использует,
array_values()
а другой используетkey()
. Чтобы выяснить, что быстрее, я написал небольшую программу:Вывод для программы на PHP 5.2 на CentOS выглядит следующим образом:
Вывод на PHP 5.3 дал аналогичные результаты. Очевидно, что использование
array_values()
намного быстрее.источник
$arrays = Array( 'Array #1' => range(0, 50000), );
Одним из способов решения этой проблемы является использование контекста
json_encode
, который уже имеет свой собственный внутренний метод различения ассоциативного массива и индексированного массива для вывода правильного JSON.Вы можете сделать это, проверив, является ли первый символ, возвращаемый после кодирования,
{
(ассоциативный массив) или[
(индексированный массив).источник
Уже есть много ответов, но вот метод, на который опирается Laravel в своем классе Arr:
Источник: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php
источник
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]
). Надеюсь, это понятно (сложно объяснить в комментариях, по крайней мере, для меня)Быстро, лаконично и эффективно работает с памятью. Никаких дорогих сравнений, вызовов функций или копирования массивов.
источник
Используя расширение xarray PHP
Вы можете сделать это очень быстро (примерно в 30+ раз быстрее в PHP 5.6):
Или:
источник
Я знаю, что немного бессмысленно добавлять ответ в эту огромную очередь, но вот читаемое решение O (n), которое не требует дублирования каких-либо значений:
Вместо того, чтобы проверять ключи, чтобы увидеть, все ли они числовые, вы перебираете ключи, которые будут там для числового массива, и убедитесь, что они существуют.
источник
[1,2,null,4]
потерпит неудачу, но это правильный массив. поэтому я добавил некоторые улучшения в stackoverflow.com/a/25206156/501831 сarray_key_exists
проверкой на добавление )isset()
это неправильный инструмент, потому что он вернет false, если значение установлено, ноnull
, как указано @lazycommit.Мое решение:
array_merge
в одном массиве будут переиндексированы всеinteger
ключи, но не другие. Например:Таким образом, если создается список (неассоциативный массив),
['a', 'b', 'c']
то значение удаляется, аunset($a[1])
затемarray_merge
вызывается, список переиндексируется, начиная с 0.источник
O(n)
в дополнительной памяти (так как он создал несколько новых массивов с таким количеством элементов$array
), ответ не решает неоднозначность задаваемого вопроса и не объясняет, как именно он определяет список / неассоциативный массив, и даже если ни один из этих пунктов не был правдой, неясно, добавляет ли это какую-либо ценность по сравнению с другими уже опубликованными ответами.После некоторого локального бенчмаркинга, отладки, проверки компилятора, профилирования и злоупотребления 3v4l.org для бенчмаркинга на нескольких версиях (да, я получил предупреждение об остановке) и сравнения со всеми вариантами, которые я смог найти ...
Я даю вам органически полученную тестовую функцию ассоциативного массива сценария с наилучшим средним и наихудшим случаем, которая в худшем случае примерно так же хороша или лучше, чем все остальные сценарии среднего случая.
С https://3v4l.org/rkieX :
источник
Вот метод, который я использую:
Обратите внимание, что это не учитывает особых случаев, таких как:
Извините, не могу помочь вам с этим. Он также несколько эффективен для массивов приличного размера, поскольку не создает ненужных копий. Именно эти мелочи делают Python и Ruby намного приятнее в написании ...: P
источник
Оба эти примера, набравшие наибольшее количество баллов, работают некорректно с такими массивами, как
$array = array('foo' => 'bar', 1)
источник
Это тоже будет работать ( демо ):
Обратите внимание, что основной смысл этого ответа - информировать вас о существовании,
SplFixedArray
а не поощрять вас использовать исключения для подобных тестов.источник
Я думаю, что определение скалярного массива будет варьироваться в зависимости от приложения. То есть некоторые приложения потребуют более строгого понимания того, что называется скалярным массивом, а некоторые приложения требуют более свободного понимания.
Ниже я представляю 3 метода различной строгости.
источник
Еще один пост от источника . Подходит кодировка
json_encode
(иbson_encode
). То же самое относится и к соблюдению javascript Array.источник
isset
иarray_key_exists
? Разве последнего не будет достаточно?isset()
проверка здесь полностью избыточна.isset()
быстрее чемarray_key_exists()
. см ilia.ws/archives/...null
s, но также не так вероятно, что у вас достаточно большой массив, чтобы была заметная разница в производительности. с помощью обеих проверокjson_encode
, вы могли бы просто проверить первый символ строки, возвращенноеjson_encode($your_arr)
- будь то[
или{
;-)Может ли это быть решением?
Предостережение заключается в том, что курсор массива сбрасывается, но я бы сказал, что, вероятно, функция используется до того, как массив будет даже пройден или использован.
источник
array("a", "b")
иarray("a", "b" => "B")
только проверяет первый ключ. Кстати,is_long
это просто псевдонимis_int
.[7 => 'foo', 2 => 'bar']
как «смешанный» массив, который частично, но не «чисто» последовательный. Это кажется мне совершенно неправильным использованием слов.Многие решения здесь элегантны и симпатичны, но плохо масштабируются и требуют большого объема памяти или ресурсов процессора. Большинство из них создают 2 новые точки данных в памяти с этим решением с обеих сторон сравнения. Чем больше массив, тем сложнее и дольше используются процесс и память, и вы теряете преимущество оценки короткого замыкания. Я провел некоторое тестирование с несколькими разными идеями. Попытка избегать array_key_exists, поскольку это дорого, а также избегать создания новых больших наборов данных для сравнения. Я чувствую, что это простой способ определить, является ли массив последовательным.
Вы запускаете один счетчик в основном массиве и сохраняете одно целое число. Затем вы перебираете массив и проверяете точное совпадение, перебирая счетчик. Вы должны иметь от 1 до подсчета. В случае сбоя происходит короткое замыкание, что повышает производительность, когда оно ложно.
Первоначально я делал это с помощью цикла for и проверял isset ($ arr [$ i]), но это не обнаружит нулевые ключи, для которых требуются array_key_exists, и, как мы знаем, это худшая функция для скорости.
Постоянно обновляя переменные через foreach, чтобы проверять вместе с итератором, не превышающим его целочисленный размер, давайте использовать PHP, он встроен в оптимизацию памяти, кеширование и сборку мусора, чтобы поддерживать очень низкое использование ресурсов.
Кроме того, я утверждаю, что использование array_keys в foreach глупо, когда вы можете просто запустить $ key => $ value и проверить ключ. Зачем создавать новую точку данных? Когда вы абстрагируете ключи массива, вы сразу же потребляете больше памяти.
источник
ответы уже даны, но есть слишком много дезинформации о производительности. Я написал этот небольшой тестовый скрипт, который показывает, что метод foreach является самым быстрым.
Отказ от ответственности: следующие методы были скопированы из других ответов
Результаты:
источник
Или вы можете просто использовать это:
который проверит, содержит ли массив какой-либо нечисловой ключ или:
проверить, является ли массив строго последовательным (содержит автоматически сгенерированные целые ключи от 0 до n-1 )
используя эту библиотеку.
источник
Если в PHP нет встроенной функции для этого, вы не сможете сделать это менее чем за O (n) - перечисление всех ключей и проверка целочисленного типа. На самом деле, вы также хотите убедиться, что дыр нет, поэтому ваш алгоритм может выглядеть так:
Но зачем? Просто предположите, что массив того типа, который вы ожидаете. Если это не так, это просто взорвется вам в лицо - это динамическое программирование для вас! Протестируй свой код и все будет хорошо ...
источник
Я сравниваю разницу между ключами массива и ключами результата array_values () массива, который всегда будет массивом с целочисленными индексами. Если ключи одинаковы, это не ассоциативный массив.
источник
O(n)
дополнительную память, когда$array
естьn
предметы, и письмо(someboolean) ? false : true
вместо того, чтобы!someboolean
ужасно и безвозмездно многословно.