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

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

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

这:

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

当前回答

从源头再来一个。 json_encode(和bson_encode)的拟合编码。javascript数组的一致性也是如此。

function isSequential($value){
    if(is_array($value) || ($value instanceof \Countable && $value instanceof \ArrayAccess)){
        for ($i = count($value) - 1; $i >= 0; $i--) {
            if (!isset($value[$i]) && !array_key_exists($i, $value)) {
                return false;
            }
        }
        return true;
    } else {
        throw new \InvalidArgumentException(
            sprintf('Data type "%s" is not supported by method %s', gettype($value), __METHOD__)
        );
    }
}

其他回答

除非PHP有这样的内置功能,否则您无法在小于O(n)的时间内完成—枚举所有键并检查整数类型。事实上,你还想确保没有漏洞,所以你的算法可能是这样的:

for i in 0 to len(your_array):
    if not defined(your-array[i]):
        # this is not an array array, it's an associative array :)

但为什么要麻烦呢?只需假设数组是您所期望的类型。如果不是,它就会在你面前爆炸——这就是动态编程!测试你的代码,一切都会很好……

我想出了下一个方法:

function isSequential(array $list): bool
{
    $i = 0;
    $count = count($list);
    while (array_key_exists($i, $list)) {
        $i += 1;
        if ($i === $count) {
            return true;
        }
    }

    return false;
}


var_dump(isSequential(array())); // false
var_dump(isSequential(array('a', 'b', 'c'))); // true
var_dump(isSequential(array("0" => 'a', "1" => 'b', "2" => 'c'))); // true
var_dump(isSequential(array("1" => 'a', "0" => 'b', "2" => 'c'))); // true
var_dump(isSequential(array("1a" => 'a', "0b" => 'b', "2c" => 'c'))); // false
var_dump(isSequential(array("a" => 'a', "b" => 'b', "c" => 'c'))); // false

*注意空数组不被认为是一个连续数组,但我认为这是好的,因为空数组就像0 -不管它是正负,它是空的。

与上面列出的一些方法相比,这种方法的优点如下:

它不涉及数组的复制(有人在这个要点https://gist.github.com/Thinkscape/1965669中提到array_values不涉及复制-什么!??它确实如此-如下所示) 对于更大的数组,它更快,同时对内存更友好

我使用了Artur Bodera提供的基准测试,其中我将其中一个数组更改为1M个元素(array_fill(0, 1000000, uniqid()), //大数字数组)。

以下是100次迭代的结果:

PHP 7.1.16 (cli) (built: Mar 31 2018 02:59:59) ( NTS )

Initial memory: 32.42 MB
Testing my_method (isset check) - 100 iterations
  Total time: 2.57942 s
  Total memory: 32.48 MB

Testing method3 (array_filter of keys) - 100 iterations
  Total time: 5.10964 s
  Total memory: 64.42 MB

Testing method1 (array_values check) - 100 iterations
  Total time: 3.07591 s
  Total memory: 64.42 MB

Testing method2 (array_keys comparison) - 100 iterations
  Total time: 5.62937 s
  Total memory: 96.43 MB

*方法的排序基于它们的内存消耗

**我使用echo“Total memory:”。Number_format (memory_get_peak_usage()/1024/ 1024,2) . "MB \ n”;显示内存使用情况

仅仅检查数组是否有非整数键(而不是数组是否按顺序索引或零索引):

function has_string_keys(array $array) {
  return count(array_filter(array_keys($array), 'is_string')) > 0;
}

如果至少有一个字符串键,$array将被视为一个关联数组。

几天前我又遇到了这个问题,我想利用array_merge特殊属性:

如果输入数组具有相同的字符串键,则该键的后一个值将覆盖前一个值。但是,如果数组包含数字键,则后一个值不会覆盖原始值,而是被追加。输入数组中具有数字键的值将使用结果数组中从0开始的递增键重新编号。 所以为什么不使用:

function Is_Indexed_Arr($arr){
    $arr_copy = $arr;
    if((2*count($arr)) == count(array_merge($arr, $arr_copy))){
        return 1;
    }
    return 0;
}
function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}

快速、简洁、高效记忆。没有昂贵的比较、函数调用或数组复制。