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

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

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

这:

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

当前回答

Mark Amery的改进

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

其他回答

我很惊讶没有人提到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

在这里阅读更多关于这个函数的信息。

一种廉价而肮脏的方法是这样检查:

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

or

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

这个问题中的许多评论者不理解PHP中的数组是如何工作的。从数组文档:

键可以是整数,也可以是字符串。如果一个键是一个整数的标准表示,它将被这样解释(即。“8”解释为8,“08”解释为“08”)。key中的浮点数被截断为整数。在PHP中,索引数组和关联数组类型是相同的类型,它们都可以包含整数和字符串索引。

换句话说,没有数组键“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作为数组键,它会被无声地转换为“”)。

Mark Amery的改进

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

大多数答案的时间/空间复杂度都不是最佳的,或者语义正在发生变化。所以,这里有另一个最快和功能最正确的解决方案:

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

与其他答案相比,这个答案有以下优点:

O(1)的空间复杂度(这里很多答案使用O(n)个空间!) 不对键应用相等性(这是一种不必要且代价高昂的操作) 将输入数组视为不可变(许多答案通过应用突变函数隐式创建了一个副本) 使用函数array_key_exists代替isset(记住,isset额外检查'is not null',从而改变语义) 最坏情况时间复杂度为O(n)(这里许多答案的最佳情况时间复杂度为O(n))