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

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

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

这:

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

当前回答

实际上,我发现自己遇到了类似的情况,试图获取一个数组并将其解析为XML。XML元素名称不能以数字开头——我发现的代码片段不能正确处理带有数字索引的数组。

我的具体情况如下

上面@null (http://stackoverflow .com/a/173589/293332)提供的答案实际上非常接近。我对它被否决感到沮丧:那些不懂正则表达式的人过着非常令人沮丧的生活。

总之,根据他的回答,我得出了以下结论:

/** 
 * Checks if an array is associative by utilizing REGEX against the keys
 * @param   $arr    <array> Reference to the array to be checked
 * @return  boolean
 */     
private function    isAssociativeArray( &$arr ) {
    return  (bool)( preg_match( '/\D/', implode( array_keys( $arr ) ) ) );
}

更多细节请参见PCRE转义序列和PCRE语法页面。

我的特殊情况

这是我正在处理的一个示例数组:

Case A
return  array(
    "GetInventorySummary"  => array(
        "Filters"  => array( 
            "Filter"  => array(
                array(
                    "FilterType"  => "Shape",
                    "FilterValue"  => "W",
                ),
                array(
                    "FilterType"  => "Dimensions",
                    "FilterValue"  => "8 x 10",
                ),
                array(
                    "FilterType"  => "Grade",
                    "FilterValue"  => "A992",
                ),
            ),
        ),
        "SummaryField"  => "Length",
    ),
);

问题是过滤器键是可变的。例如:

Case B
return  array(
    "GetInventorySummary"  => array(
        "Filters"  => array( 
            "Filter"  => array(
                "foo"   =>  "bar",
                "bar"   =>  "foo",
            ),
        ),
        "SummaryField"  => "Length",
    ),
);

为什么我需要协会。检查数组

如果我要转换的数组像情况A一样,我想要返回的是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GetInventorySummary>
    <Filters>
        <Filter>
            <FilterType>Shape</FilterType>
            <FilterValue>W</FilterValue>
        </Filter>
        <Filter>
            <FilterType>Dimensions</FilterType>
            <FilterValue>8 x 10</FilterValue>
        </Filter>
        <Filter>
            <FilterType>Grade</FilterType>
             <FilterValue>A992</FilterValue>
        </Filter>
    </Filters>
    <SummaryField>Length</SummaryField>
</GetInventorySummary>

... 然而,如果我要转换的数组像Case B一样,我想要返回的是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<GetInventorySummary>
    <Filters>
        <Filter>
            <foo>bar</foo>
            <bar>foo</bar>
        </Filter>
    </Filters>
    <SummaryField>Length</SummaryField>
</GetInventorySummary>

其他回答

我很惊讶没有人提到array_key_first()

对于您的测试用例:

$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
$isIndexedArray = is_int( array_key_first($sequentialArray) ); // true

$assocArray = array('fruit1' => 'apple', 
                'fruit2' => 'orange', 
                'veg1' => 'tomato', 
                'veg2' => 'carrot');

$isIndexedArray = is_int( array_key_first($assocArray) ); // false

在这里阅读更多关于这个函数的信息。

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

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

这是解决方案吗?

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

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

这是函数-

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相关函数的另一种方式。我还没有检查这个解决方案在性能方面如何与其他已经在这里发布的解决方案相比。但它确实帮助我解决了这个问题。希望这能有所帮助。

这也会工作(演示):

function array_has_numeric_keys_only(array $array)
{
    try {
        SplFixedArray::fromArray($array, true);
    } catch (InvalidArgumentException $e) {
        return false;
    }
    return true;
}

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