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

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

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

这:

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

当前回答

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

参考

其他回答

简单地说,你可以通过以下步骤检查数组是否关联

使用array_keys()将数组的所有键转换为一个数组 使用array_filter()和从数组中过滤非数字键 is_numeric () 比较过滤数组和实际数组中的元素数量,如果两个数组中的元素数量不相等,则为关联数组。

以上步骤的功能如下所示。

 function isAssociative(array $array)
    {
        return count(array_filter(array_keys($array), function($v){return is_numeric($v);})) !== count($array));
    }

这个函数可以处理:

索引有孔的数组(例如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;
}

解决这个问题的一种方法是利用json_encode,它已经有自己的内部方法来区分关联数组和索引数组,以便输出正确的JSON。

可以通过检查编码后返回的第一个字符是{(关联数组)还是[(索引数组)来做到这一点。

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}

这也会工作(演示):

function array_has_numeric_keys_only(array $array)
{
    try {
        SplFixedArray::fromArray($array, true);
    } catch (InvalidArgumentException $e) {
        return false;
    }
    return true;
}

请注意,这个答案的主要观点是告诉你SplFixedArray的存在,而不是鼓励你对这些类型的测试使用异常。

只是补充我的意见,我认为它应该是相当有效的基于@nonsensei的基准,以及清晰易读:

function is_associative(array $array): bool
{
    foreach ($array as $key => $value)
    {
        if (!is_string($key)) return false;
    }
    return true;
}