Как проверить, является ли массив PHP ассоциативным или последовательным? - PullRequest
724 голосов
/ 06 октября 2008

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

В принципе, я хочу иметь возможность различать это:

$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');

и это:

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

Ответы [ 51 ]

7 голосов
/ 08 октября 2010

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

  • массив с отверстиями в индексе (например, 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;
}
7 голосов
/ 20 февраля 2013

Я заметил два популярных подхода к этому вопросу: один использует 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 выглядит следующим образом:

Время, затраченное по методу № 1 = 10,745 мс
Время, затраченное по методу № 2 = 18,239 мс

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

6 голосов
/ 20 января 2016

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

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

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}
5 голосов
/ 05 апреля 2017

Ответов уже много, но вот метод, на который опирается 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

5 голосов
/ 08 марта 2016
function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}

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

4 голосов
/ 16 октября 2015

Используя xarray расширение PHP

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

if (array_is_indexed($array)) {  }

Или:

if (array_is_assoc($array)) {  }
3 голосов
/ 09 июля 2014

Мое решение:

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.

2 голосов
/ 05 февраля 2011

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

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

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

2 голосов
/ 22 июля 2011

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

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

2 голосов
/ 16 мая 2012
<?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)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...