PHP将所有数组都视为关联数组,因此没有任何内置函数。谁能推荐一种相当有效的方法来检查数组是否“是一个列表”(只包含从0开始的数字键)?

基本上,我希望能够区分这些:

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

这:

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

当前回答

function isAssoc($arr)
{
    $a = array_keys($arr);
    for($i = 0, $t = count($a); $i < $t; $i++)
    {
        if($a[$i] != $i)
        {
            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";

该程序在CentOS上的PHP 5.2上的输出如下:

方法#1所花费的时间= 10.745ms 方法#2所花费的时间= 18.239ms

PHP 5.3上的输出产生了类似的结果。显然,使用array_values()要快得多。

当然,这是一个更好的选择。

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

简单和性能友好的解决方案,只检查第一个键。

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

            break;
        }
    }

    return false;
}

我的解决方案是获得如下数组的键,并检查是否键不是整数:

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

因此,将它与评分最高的答案中提到的一系列数字进行比较并不是一个好主意。它总是说它是一个哈希数组如果你试着比较键和范围。

下面是另一个简单但功能强大的逻辑(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;
}