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

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

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

这:

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

当前回答

我的解决方案:

function isAssociative(array $array)
{
    return array_keys(array_merge($array)) !== range(0, count($array) - 1);
}

单个数组上的Array_merge将重新索引所有整数键,但不包括其他键。例如:

array_merge([1 => 'One', 3 => 'Three', 'two' => 'Two', 6 => 'Six']);

// This will returns [0 => 'One', 1 => 'Three', 'two' => 'Two', 2 => 'Six']

因此,如果创建了一个列表(非关联数组)['a', 'b', 'c'],则删除一个值unset($a[1]),然后调用array_merge,从0开始重新索引列表。

其他回答

我比较数组的键值和数组的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 array_has_numeric_keys_only(array $array)
{
    try {
        SplFixedArray::fromArray($array, true);
    } catch (InvalidArgumentException $e) {
        return false;
    }
    return true;
}

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

有时你可以只检查第一个数组的Key是否为0。

$isSequential = array_keys($arr)[0] ===

,或更快,但更冗长的版本:

重置(arr);$isSequential = key($arr) === 0

这是解决方案吗?

  public static function isArrayAssociative(array $array) {
      reset($array);
      return !is_int(key($array));
  }

需要注意的是,数组光标被重置了,但我想说的是,这个函数可能在数组被遍历或使用之前就被使用了。

我已经使用了array_keys($obj) !== range(0, count($obj) - 1)和array_values($arr) !== $arr(它们是彼此的对偶,尽管第二个比第一个更便宜),但对于非常大的数组都失败了。

这是因为array_keys和array_values都是非常昂贵的操作(因为它们构建了一个大小与原始数组大致相同的全新数组)。

下面的函数比上面提供的方法更健壮:

function array_type( $obj ){
    $last_key = -1;
    $type = 'index';
    foreach( $obj as $key => $val ){
        if( !is_int( $key ) || $key < 0 ){
            return 'assoc';
        }
        if( $key !== $last_key + 1 ){
            $type = 'sparse';
        }
        $last_key = $key;
    }
    return $type;
}

还要注意,如果你不关心区分稀疏数组和关联数组,你可以简单地从两个if块中返回'assoc'。

最后,虽然这可能看起来没有本页上的许多“解决方案”那么“优雅”,但实际上它的效率要高得多。几乎任何关联数组都会立即被检测到。只有索引数组才会被彻底检查,上面列出的方法不仅会彻底检查索引数组,还会复制它们。