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

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

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

这:

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

当前回答

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

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

其他回答

下面是另一个简单但功能强大的逻辑(Laravel框架在内部机制中也使用了这个逻辑)

/**
 * Determines if an array is associative.
 * @param  array  $array
 * @return bool
 */
function isAssoc(array $array)
{
    $keys = array_keys($array);

    return array_keys($keys) !== $keys;
}
function is_associative($arr) {
  return (array_merge($arr) !== $arr || count(array_filter($arr, 'is_string', ARRAY_FILTER_USE_KEY)) > 0);
}

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

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

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

A lot of the solutions here are elegant and pretty, but don't scale well, and are memory intensive or CPU intensive. Most are creating 2 new data points in memory with this solution from both sides of the comparison. The larger the array the harder and longer the process and memory used, and you lose the benefit of short circuit evaluation. I Did some testing with a few different ideas. Trying to avoid array_key_exists as it is costly, and also avoiding creating new large datasets to compare. I feel this is a simple way to tell if an array is sequential.

public function is_sequential( $arr = [] ){
    if( !is_array( $arr ) || empty( $arr ) ) return false;

    $i = 0;

    $total = count( $arr );

    foreach( $arr as $key => $value ) if( $key !== $i++ ) return false;

    return true;
}

在主数组上运行一个计数并存储一个整数。然后循环遍历数组并在迭代计数器时检查精确匹配。你应该从1开始计数。如果它失败了,它会短路,当它为假时,它会给你性能的提升。

最初,我这样做了一个for循环和检查isset($arr[$ I]),但这将不检测null键,这需要array_key_exists,我们知道,这是最糟糕的函数使用速度。

通过foreach不断更新变量,并检查迭代器,永远不会超过它的整数大小,让PHP使用它内置的内存优化,缓存和垃圾收集,以保持非常低的资源使用。

此外,我认为在foreach中使用array_keys是愚蠢的,因为您可以简单地运行$key => $value并检查键。为什么要创建新的数据点?一旦抽象出数组键,就会立即消耗更多内存。

检测关联数组(哈希数组)的最佳函数

<?php
function is_assoc($arr) { return (array_values($arr) !== $arr); }
?>