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

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

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

这:

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

当前回答

修改最流行的答案。 这需要更多的处理,但更准确。

<?php
//$a is a subset of $b
function isSubset($a, $b)
{
    foreach($a =>$v)
        if(array_search($v, $b) === false)
            return false;

    return true;

    //less effecient, clearer implementation. (uses === for comparison)
    //return array_intersect($a, $b) === $a;
}

function isAssoc($arr)
{
    return !isSubset(array_keys($arr), range(0, count($arr) - 1));
}

var_dump(isAssoc(array('a', 'b', 'c'))); // false
var_dump(isAssoc(array(1 => 'a', 0 => 'b', 2 => 'c'))); // false
var_dump(isAssoc(array("0" => 'a', "1" => 'b', "2" => 'c'))); // false 
//(use === in isSubset to get 'true' for above statement)
var_dump(isAssoc(array("a" => 'a', "b" => 'b', "c" => 'c'))); // true
?>

其他回答

我想出了下一个方法:

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”;显示内存使用情况

我比较数组的键值和数组的array_values()结果的键值之间的差异,数组始终是一个具有整数下标的数组。如果键是相同的,它就不是一个关联数组。

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}

你问了两个不完全等价的问题:

首先,如何确定数组是否只有数字键 其次,如何确定数组是否具有从0开始的连续数字键

考虑一下哪些行为是你真正需要的。(也许对你来说,这两种方法都可以。)

第一个问题(简单地检查所有键是否都是数字)由kurO船长回答得很好。

对于第二个问题(检查数组是否为0索引和顺序),您可以使用以下函数:

function isAssoc(array $arr)
{
    if (array() === $arr) return false;
    return array_keys($arr) !== range(0, count($arr) - 1);
}

var_dump(isAssoc(['a', 'b', 'c'])); // false
var_dump(isAssoc(["0" => 'a', "1" => 'b', "2" => 'c'])); // false
var_dump(isAssoc(["1" => 'a', "0" => 'b', "2" => 'c'])); // true
var_dump(isAssoc(["a" => 'a', "b" => 'b', "c" => 'c'])); // true

通过使用xarray PHP扩展

你可以非常快地做到这一点(在PHP 5.6中大约快30倍):

if (array_is_indexed($array)) {  }

Or:

if (array_is_assoc($array)) {  }

我知道在这个庞大的队列中添加答案有点毫无意义,但这里有一个可读的O(n)解决方案,不需要复制任何值:

function isNumericArray($array) {
    $count = count($array);
    for ($i = 0; $i < $count; $i++) {
        if (!isset($array[$i])) {
            return FALSE;
        }
    }
    return TRUE;
}

不是检查键是否都是数字,而是遍历数字数组的键并确保它们存在。