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

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

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

这:

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

当前回答

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

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

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

其他回答

这个函数可以处理:

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

答案已经给出了,但关于表现的虚假信息太多了。 我写了这个小的基准测试脚本,它显示foreach方法是最快的。

免责声明:以下方法是从其他答案复制粘贴的

<?php

function method_1(Array &$arr) {
    return $arr === array_values($arr);
}

function method_2(Array &$arr) {
    for (reset($arr), $i = 0; key($arr) !== $i++; next($arr));
    return is_null(key($arr));
}

function method_3(Array &$arr) {
    return array_keys($arr) === range(0, count($arr) - 1);
}

function method_4(Array &$arr) {
    $idx = 0;
    foreach( $arr as $key => $val ){
        if( $key !== $idx )
            return FALSE;
        $idx++;
    }
    return TRUE;
}




function benchmark(Array $methods, Array &$target){    
    foreach($methods as $method){
        $start = microtime(true);
        for ($i = 0; $i < 1000; $i++)
            $dummy = call_user_func($method, $target);

        $end = microtime(true);
        echo "Time taken with $method = ".round(($end-$start)*1000.0,3)."ms\n";
    }
}



$targets = [
    'Huge array' => range(0, 30000),
    'Small array' => range(0, 1000),
];
$methods = [
    'method_1',
    'method_2',
    'method_3',
    'method_4',
];
foreach($targets as $targetName => $target){
    echo "==== Benchmark using $targetName ====\n";
    benchmark($methods, $target);
    echo "\n";
}

结果:

==== Benchmark using Huge array ====
Time taken with method_1 = 5504.632ms
Time taken with method_2 = 4509.445ms
Time taken with method_3 = 8614.883ms
Time taken with method_4 = 2720.934ms

==== Benchmark using Small array ====
Time taken with method_1 = 77.159ms
Time taken with method_2 = 130.03ms
Time taken with method_3 = 160.866ms
Time taken with method_4 = 69.946ms

下面是我使用的方法:

function is_associative ( $a )
{
    return in_array(false, array_map('is_numeric', array_keys($a)));
}

assert( true === is_associative(array(1, 2, 3, 4)) );

assert( false === is_associative(array('foo' => 'bar', 'bar' => 'baz')) );

assert( false === is_associative(array(1, 2, 3, 'foo' => 'bar')) );

注意,这并不包括特殊情况,如:

$a = array( 1, 2, 3, 4 );

unset($a[1]);

assert( true === is_associative($a) );

对不起,我帮不了你。对于大小合适的数组,它也有一定的性能,因为它不会产生不必要的拷贝。正是这些小细节使得Python和Ruby编写起来更加方便……: P

我认为标量数组的定义因应用程序而异。也就是说,一些应用程序将需要更严格的定义标量数组,而一些应用程序将需要更宽松的定义。

下面我将介绍3种不同严格程度的方法。

<?php
/**
 * Since PHP stores all arrays as associative internally, there is no proper
 * definition of a scalar array.
 * 
 * As such, developers are likely to have varying definitions of scalar array,
 * based on their application needs.
 * 
 * In this file, I present 3 increasingly strict methods of determining if an
 * array is scalar.
 * 
 * @author David Farrell <DavidPFarrell@gmail.com>
 */

/**
 * isArrayWithOnlyIntKeys defines a scalar array as containing
 * only integer keys.
 * 
 * If you are explicitly setting integer keys on an array, you
 * may need this function to determine scalar-ness.
 * 
 * @param array $a
 * @return boolean
 */ 
function isArrayWithOnlyIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    foreach ($a as $k => $v)
        if (!is_int($k))
            return false;
    return true;
}

/**
 * isArrayWithOnlyAscendingIntKeys defines a scalar array as
 * containing only integer keys in ascending (but not necessarily
 * sequential) order.
 * 
 * If you are performing pushes, pops, and unsets on your array,
 * you may need this function to determine scalar-ness.
 * 
 * @param array $a
 * @return boolean
 */ 
function isArrayWithOnlyAscendingIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    $prev = null;
    foreach ($a as $k => $v)
    {
        if (!is_int($k) || (null !== $prev && $k <= $prev))
            return false;
        $prev = $k;
    }
    return true;
}

/**
 * isArrayWithOnlyZeroBasedSequentialIntKeys defines a scalar array
 * as containing only integer keys in sequential, ascending order,
 * starting from 0.
 * 
 * If you are only performing operations on your array that are
 * guaranteed to either maintain consistent key values, or that
 * re-base the keys for consistency, then you can use this function.
 * 
 * @param array $a
 * @return boolean
 */
function isArrayWithOnlyZeroBasedSequentialIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    $i = 0;
    foreach ($a as $k => $v)
        if ($i++ !== $k)
            return false;
    return true;
}

这是函数-

public function is_assoc_array($array){

    if(is_array($array) !== true){
        return false;
    }else{

        $check = json_decode(json_encode($array));

        if(is_object($check) === true){
            return true;
        }else{
            return false;
        }

    }

}

一些例子

    print_r((is_assoc_array(['one','two','three']))===true?'Yes':'No'); \\No
    print_r(is_assoc_array(['one'=>'one','two'=>'two','three'=>'three'])?'Yes':'No'); \\Yes
    print_r(is_assoc_array(['1'=>'one','2'=>'two','3'=>'three'])?'Yes':'No'); \\Yes
    print_r(is_assoc_array(['0'=>'one','1'=>'two','2'=>'three'])?'Yes':'No'); \\No

在其中一个答案中@devios1有一个类似的解决方案,但这只是使用PHP的内置json相关函数的另一种方式。我还没有检查这个解决方案在性能方面如何与其他已经在这里发布的解决方案相比。但它确实帮助我解决了这个问题。希望这能有所帮助。