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

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

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

这:

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

当前回答

如果你只是寻找非数字键(无论顺序),那么你可能想尝试一下

function IsAssociative($array)
{
    return preg_match('/[a-z]/i', implode(array_keys($array)));
}

其他回答

我比较数组的键值和数组的array_values()结果的键值之间的差异,数组始终是一个具有整数下标的数组。如果键是相同的,它就不是一个关联数组。

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}

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

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

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

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

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

通过使用xarray PHP扩展

你可以非常快地做到这一点(在PHP 5.6中大约快30倍):

if (array_is_indexed($array)) {  }

Or:

if (array_is_assoc($array)) {  }

PHP 8.1增加了一个内置函数来确定数组是否是具有这些语义的列表。函数是array_is_list:

$list = ["a", "b", "c"];

array_is_list($list); // true

$notAList = [1 => "a", 2 => "b", 3 => "c"];

array_is_list($notAList); // false

$alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];

array_is_list($alsoNotAList); // false

参考