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

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

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

这:

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

当前回答

function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}

其他回答

我只是使用key()函数。观察:

<?php
var_dump(key(array('hello'=>'world', 'hello'=>'world'))); //string(5) "hello"
var_dump(key(array('world', 'world')));                  //int(0)
var_dump(key(array("0" => 'a', "1" => 'b', "2" => 'c'))); //int(0) who makes string sequetial keys anyway????
?>

因此,仅通过检查false,就可以确定数组是否是关联的。

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

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

            break;
        }
    }

    return false;
}

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

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

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

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

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

这个函数可以处理:

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