9

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

5

Проблема с определением "последовательного" массива в PHP заключается в том, что PHP рассматривает все массивы как ассоциативные, и для этого нет встроенных функций. Есть ли какие-либо рекомендации по довольно эффективному способу проверки, является ли массив "списком" (то есть содержит ли он только числовые ключи, начинающиеся с 0)?

Мне нужно уметь отличать следующий массив:

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

от следующего:

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

Как можно реализовать такую проверку?

5 ответ(ов)

4

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

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

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

1

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

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

В данном случае переменная $isIndexed будет истинной (true), если массив $arr индексированный, так как array_values удаляет любые ключи, которые не являются целыми числами, и, если массив изначально индексированный, оба массива будут равны.

0

Я использовал как 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' в обоих условиях.

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

0

Вопрос: Каковы различия в производительности и использовании памяти между следующими функциями для проверки ассоциативного массива в PHP?

Вариант 1 (по скорости):

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

Вариант 2 (по памяти):

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

Ответ:

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

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

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

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

0

В вашем коде функция checkAssoc проверяет, является ли массив ассоциативным, основываясь на ключах массива. Давайте разберем, как она работает:

function checkAssoc($array) {
    return ctype_digit(implode('', array_keys($array)));
}
  1. array_keys($array) извлекает все ключи из массива $array.
  2. implode('', ...) объединяет эти ключи в одну строку без разделителей.
  3. ctype_digit(...) проверяет, состоит ли результирующая строка только из цифр.

Таким образом, если все ключи массива являются цифровыми строками, то функция вернет true, в противном случае — false.

Однако, данный подход не является полностью надежным для определения ассоциативного массива, поскольку, например, массив с ключами 0, 1, 2 будет возвращать false, что не всегда соответствует ожиданиям. Для более точного определения ассоциативности массива, можно использовать следующий код:

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

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь