代码之家  ›  专栏  ›  技术社区  ›  emma

php数组:检查它是“key=>value”还是“value”[重复]

  •  0
  • emma  · 技术社区  · 7 年前

    PHP将所有数组视为关联数组,因此没有任何内置函数。有人能推荐一种相当有效的方法来检查数组是否只包含数字键吗?

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

    $sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
    

    还有这个:

    $assocArray = array('fruit1' => 'apple', 
                        'fruit2' => 'orange', 
                        'veg1' => 'tomato', 
                        'veg2' => 'carrot');
    
    0 回复  |  直到 6 年前
        1
  •  553
  •   Mark Amery    7 年前

    您提出了两个不完全相同的问题:

    • 首先,如何确定数组是否只有数字键
    • 其次,如何确定数组是否 相继的 数字键,从0开始

    考虑一下你真正需要哪些行为。(可能两者都是为了你的目的。)

    第一个问题(只是检查所有键是否都是数字)是 answered well by Captain kurO .

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

    function isAssoc(array $arr)
    {
        if (array() === $arr) return false;
        return array_keys($arr) !== range(0, count($arr) - 1);
    }
    
    var_dump(isAssoc(array('a', 'b', 'c'))); // false
    var_dump(isAssoc(array("0" => 'a', "1" => 'b', "2" => 'c'))); // false
    var_dump(isAssoc(array("1" => 'a', "0" => 'b', "2" => 'c'))); // true
    var_dump(isAssoc(array("a" => 'a', "b" => 'b', "c" => 'c'))); // true
    
        2
  •  415
  •   Captain kurO    9 年前

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

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

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

        3
  •  127
  •   Lars Truijens    13 年前

    当然,这是一个更好的选择。

    <?php
    $arr = array(1,2,3,4);
    $isIndexed = array_values($arr) === $arr;
    
        4
  •  73
  •   squirrel    6 年前

    这个问题中的许多注释者不理解数组如何在PHP中工作。来自 array documentation :

    键可以是整数或字符串。如果一个键是一个整数的标准表示,它将被解释为(即,“8”将被解释为8,而“08”将被解释为“08”)。键中的浮点被截断为整数。索引数组和关联数组类型在PHP中是相同的类型,它可以包含整数索引和字符串索引。

    换句话说,没有数组键“8”这样的东西,因为它总是(无声地)转换为整数8。因此,尝试区分整数和数字字符串是不必要的。

    如果希望使用最有效的方法检查数组中的非整数键,而不复制数组的一部分(如array_keys()所做的)或全部(如foreach所做的):

    function keyedNext( &$arr, &$k){
        $k = key($arr);
        return next($arr);
    }
    
    for ($k = key(reset($my_array)); is_int($k); keyedNext($my_array,$k))
        $onlyIntKeys = is_null($k);
    

    这是因为键()在当前数组位置无效时返回空值,并且空值永远不能是有效的键(如果尝试将空值用作数组键,则会自动转换为“”)。

        5
  •  38
  •   Pang    8 年前

    AS stated by the OP :

    PHP将所有数组视为关联数组

    编写一个函数来检查数组是否 结合的 。所以第一件事是: what is a key in a PHP array ?:

    这个 钥匙 可以是 整数 或A 一串 .

    这意味着有3种可能的情况:

    • 案例1。所有钥匙都是 数字 / 整数 .
    • 案例2。所有钥匙都是 .
    • 案例3。一些钥匙是 ,有些钥匙是 数字 / 整数 .

    我们可以使用以下功能检查每个案例。

    案例1:所有钥匙 数字 / 整数 .

    注释 : 此函数返回 也适用于空数组。

    //! Check whether the input is an array whose keys are all integers.
    /*!
        \param[in] $InputArray          (array) Input array.
        \return                         (bool) \b true iff the input is an array whose keys are all integers.
    */
    function IsArrayAllKeyInt($InputArray)
    {
        if(!is_array($InputArray))
        {
            return false;
        }
    
        if(count($InputArray) <= 0)
        {
            return true;
        }
    
        return array_unique(array_map("is_int", array_keys($InputArray))) === array(true);
    }
    

    案例2:所有钥匙 .

    注释 : 此函数返回 真的 也适用于空数组。

    //! Check whether the input is an array whose keys are all strings.
    /*!
        \param[in] $InputArray          (array) Input array.
        \return                         (bool) \b true iff the input is an array whose keys are all strings.
    */
    function IsArrayAllKeyString($InputArray)
    {
        if(!is_array($InputArray))
        {
            return false;
        }
    
        if(count($InputArray) <= 0)
        {
            return true;
        }
    
        return array_unique(array_map("is_string", array_keys($InputArray))) === array(true);
    }
    

    案例3。一些钥匙是 ,有些钥匙是 数字 / 整数 .

    注释 : 此函数返回 真的 也适用于空数组。

    //! Check whether the input is an array with at least one key being an integer and at least one key being a string.
    /*!
        \param[in] $InputArray          (array) Input array.
        \return                         (bool) \b true iff the input is an array with at least one key being an integer and at least one key being a string.
    */
    function IsArraySomeKeyIntAndSomeKeyString($InputArray)
    {
        if(!is_array($InputArray))
        {
            return false;
        }
    
        if(count($InputArray) <= 0)
        {
            return true;
        }
    
        return count(array_unique(array_map("is_string", array_keys($InputArray)))) >= 2;
    }
    

    如下:


    现在,对于一个数组 “正品”阵列 我们都习惯了,意思是:

    • 它的钥匙都是 数字 / 整数 .
    • 它的钥匙是 相继的 (即按步骤1递增)。
    • 它的钥匙 start from zero .

    我们可以检查以下功能。

    案例3a.钥匙 数字 / 整数 , 相继的 零基 .

    注释 : 此函数返回 也适用于空数组。

    //! Check whether the input is an array whose keys are numeric, sequential, and zero-based.
    /*!
        \param[in] $InputArray          (array) Input array.
        \return                         (bool) \b true iff the input is an array whose keys are numeric, sequential, and zero-based.
    */
    function IsArrayKeyNumericSequentialZeroBased($InputArray)
    {
        if(!is_array($InputArray))
        {
            return false;
        }
    
        if(count($InputArray) <= 0)
        {
            return true;
        }
    
        return array_keys($InputArray) === range(0, count($InputArray) - 1);
    }
    

    警告/陷阱(或者,关于PHP中数组键的更为特殊的事实)

    整数键

    这些数组的键是 integers :

    array(0 => "b");
    array(13 => "b");
    array(-13 => "b");          // Negative integers are also integers.
    array(0x1A => "b");         // Hexadecimal notation.
    

    字符串键

    这些数组的键是 strings :

    array("fish and chips" => "b");
    array("" => "b");                                   // An empty string is also a string.
    array("stackoverflow_email@example.com" => "b");    // Strings may contain non-alphanumeric characters.
    array("stack\t\"over\"\r\nflow's cool" => "b");     // Strings may contain special characters.
    array('$tα€k↔øv∈rflöw⛄' => "b");                    // Strings may contain all kinds of symbols.
    array("functіon" => "b");                           // You think this looks fine? Think again! (see https://stackoverflow.com/q/9246051/1402846)
    array("ま말轉转ДŁ" => "b");                         // How about Japanese/Korean/Chinese/Russian/Polish?
    array("fi\x0sh" => "b");                            // Strings may contain null characters.
    array(file_get_contents("https://www.google.com/images/nav_logo114.png") => "b");   // Strings may even be binary!
    

    看起来像字符串的整数键

    如果你认为钥匙在 array("13" => "b") 是一个 一串 , 你错了 . 从医生那里 here :

    包含有效整数的字符串将强制转换为整数类型。例如,键“8”实际上存储在8下。另一方面,“08”不会被强制转换,因为它不是有效的十进制整数。

    例如,这些数组的键是 整数 :

    array("13" => "b");
    array("-13" => "b");                        // Negative, ok.
    

    但这些数组的关键是 :

    array("13." => "b");
    array("+13" => "b");                        // Positive, not ok.
    array("-013" => "b");
    array("0x1A" => "b");                       // Not converted to integers even though it's a valid hexadecimal number.
    array("013" => "b");                        // Not converted to integers even though it's a valid octal number.
    array("18446744073709551616" => "b");       // Not converted to integers as it can't fit into a 64-bit integer.
    

    更重要的是,根据 doc ,

    整数的大小取决于平台,尽管最大值约为20亿是通常的值(即32位有符号)。64位平台的最大值通常约为9e18,但Windows除外,后者始终为32位。PHP不支持无符号整数。

    所以这个数组的键 可以也可以不可以 是一个 整数 -这取决于你的平台。

    array("60000000000" => "b");                // Array key could be integer or string, it can fit into a 64-bit (but not 32-bit) integer.
    

    更糟糕的是,PHP往往 婴儿车 如果整数接近2 三十一 =2147483648边界(见 bug 51430 , bug 52899 )例如,在我的本地环境(Windows7上的xampp 1.7.7上的php 5.3.8)中, var_dump(array("2147483647" => "b")) 给予

    array(1) {
        [2147483647]=>
        string(1) "b"
    }   
    

    但关于 this live demo on codepad (php 5.2.5),相同的表达式给出

    array(1) {
        ["2147483647"]=>
        string(1) "b"
    }
    

    所以关键是 整数 在一个环境中 一串 在另一个,即使 2147483647 是有效的有符号32位 整数 .

        6
  •  34
  •   Alix Axel    14 年前

    速度方面:

    function isAssoc($array)
    {
        return ($array !== array_values($array));
    }
    

    记忆方面:

    function isAssoc($array)
    {
        $array = array_keys($array); return ($array !== array_keys($array));
    }
    
        7
  •  19
  •   4 revs, 3 users 67%<br/>anon&#13;    9 年前

    实际上,最有效的方法是:

    function is_assoc($array){
       $keys = array_keys($array);
       return $keys !== array_keys($keys);
    }
    

    这是因为它将键(对于顺序数组,该键始终为0、1、2等)与键(该键将 总是 为0、1、2等)。

        8
  •  18
  •   Vladimir Prudnikov    15 年前
    function checkAssoc($array){
        return  ctype_digit( implode('', array_keys($array) ) );
    }
    
        9
  •  17
  •   TimothyAWiseman    9 年前

    我都用过了 array_keys($obj) !== range(0, count($obj) - 1) array_values($arr) !== $arr (虽然第二个比第一个便宜,但这两个都是彼此的对立面),但对于非常大的阵列来说,这两个都是失败的。

    这是因为 array_keys array_values 都是非常昂贵的操作(因为它们构建了一个全新的数组,大小与原始数组大致相同)。

    以下函数比上面提供的方法更可靠:

    function array_type( $obj ){
        $last_key = -1;
        $type = 'index';
        foreach( $obj as $key => $val ){
            if( !is_int( $key ) || $key < 0 ){
                return 'assoc';
            }
            if( $key !== $last_key + 1 ){
                $type = 'sparse';
            }
            $last_key = $key;
        }
        return $type;
    }
    

    另外请注意,如果不想区分稀疏数组和关联数组,只需返回 'assoc' 从两者 if 阻碍。

    最后,虽然这看起来比本页上的许多“解决方案”要“优雅”得多,但实际上它的效率要高得多。几乎所有的关联数组都会立即被检测到。只有索引数组才会被彻底检查,上面概述的方法不仅彻底检查索引数组,而且会复制它们。

        10
  •  13
  •   Niels Ockeloen    13 年前

    我认为下面两个函数是检查“数组是关联的还是数值的”的最佳方法。由于“numeric”只能表示数字键或顺序数字键,因此下面列出了两个检查任一条件的函数:

    function is_indexed_array(&$arr) {
      for (reset($arr); is_int(key($arr)); next($arr));
      return is_null(key($arr));
    }
    
    function is_sequential_array(&$arr, $base = 0) {
      for (reset($arr), $base = (int) $base; key($arr) === $base++; next($arr));
      return is_null(key($arr));
    }
    

    第一个函数检查每个键是否为整数值。第二个函数检查每个键是否为整数值,另外检查所有键是否从$base开始连续,默认值为0,因此,如果不需要指定另一个基值,则可以省略。如果读取指针移过数组的结尾($my_array),则键($my_array)返回空值,这将结束for循环,如果所有键都是整数,则使for循环后面的语句返回真值。如果不是,则循环将提前结束,因为键的类型为string,并且for循环之后的语句将返回false。后一个函数在每次比较后再加上一个到$base,以便能够检查下一个键的值是否正确。通过严格的比较,还可以检查键是否为整数类型。当省略$base或确保只使用整数调用它时,可以省略for循环第一节中的$base=(int)$base部分。但因为我不能确定每个人,所以我把它放了进去。无论如何,语句只执行一次。我认为这些是最有效的解决方案:

    • 内存方面:不复制数据或键范围。做一个数组值或数组键可能看起来更短(代码更少),但记住一旦你做了那个调用在后台会发生什么。是的,有比其他一些解决方案更多的(可见的)声明,但这不重要,是吗?
    • 时间方面:除了复制/提取数据和/或键也需要时间之外,此解决方案比执行foreach更有效。同样,foreach对某些人来说似乎更有效,因为它的符号更短,但在后台foreach还调用reset、key和next来执行循环。但除此之外,它还调用valid来检查结束条件,这在这里由于与整数检查的组合而被避免。

    请记住,数组键只能是整数或字符串,而严格数字字符串(如“1”(但不是“01”)将被转换为整数。这使得检查整数键成为除计数之外唯一需要的操作,如果您希望数组是连续的。当然,如果被索引的数组返回false,则可以将该数组视为关联数组。我说“看见”,因为事实上他们都是。

        11
  •  7
  •   LazNiko    14 年前

    此功能可以处理:

    • 索引中有孔的数组(例如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;
    }
    
        12
  •  7
  •   Manu M.    12 年前

    我注意到这个问题有两种流行的方法:一种是 array_values() 以及其他用途 key() . 为了找出哪个更快,我写了一个小程序:

    $arrays = Array(
      'Array #1' => Array(1, 2, 3, 54, 23, 212, 123, 1, 1),
      'Array #2' => Array("Stack", 1.5, 20, Array(3.4)),
      'Array #3' => Array(1 => 4, 2 => 2),
      'Array #4' => Array(3.0, "2", 3000, "Stack", 5 => "4"),
      'Array #5' => Array("3" => 4, "2" => 2),
      'Array #6' => Array("0" => "One", 1.0 => "Two", 2 => "Three"),
      'Array #7' => Array(3 => "asdf", 4 => "asdf"),
      'Array #8' => Array("apple" => 1, "orange" => 2),
    );
    
    function is_indexed_array_1(Array &$arr) {
      return $arr === array_values($arr);
    }
    
    function is_indexed_array_2(Array &$arr) {
      for (reset($arr), $i = 0; key($arr) === $i++; next($arr))
        ;
      return is_null(key($arr));
    }
    
    // Method #1
    $start = microtime(true);
    for ($i = 0; $i < 1000; $i++) {
      foreach ($arrays as $array) {
        $dummy = is_indexed_array_1($array);
      }
    }
    $end = microtime(true);
    echo "Time taken with method #1 = ".round(($end-$start)*1000.0,3)."ms\n";
    
    // Method #2
    $start = microtime(true);
    for ($i = 0; $i < 1000; $i++) {
      foreach ($arrays as $array) {
        $dummy = is_indexed_array_2($array);
      }
    }
    $end = microtime(true);
    echo "Time taken with method #1 = ".round(($end-$start)*1000.0,3)."ms\n";
    

    CentOS上php 5.2上程序的输出如下:

    方法1所用时间=10.745ms
    方法2所用时间=18.239ms

    php 5.3上的输出产生了类似的结果。显然使用 数组_值() 更快。

        13
  •  6
  •   MAChitgarha    7 年前

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

    您可以通过检查编码后返回的第一个字符是否是 { (关联数组)或 [ (索引数组)。

    // Too short :)
    function is_assoc($arr) {
        ksort($arr);
        return json_encode($arr)[0] === '{';
    }
    
        14
  •  5
  •   Jesse    9 年前
    function array_is_assoc(array $a) {
        $i = 0;
        foreach ($a as $k => $v) {
            if ($k !== $i++) {
                return true;
            }
        }
        return false;
    }
    

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

        15
  •  5
  •   Ben    7 年前

    已经有很多答案,但下面是Laravel在其ARR类中所依赖的方法:

    /**
     * Determines if an array is associative.
     *
     * An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
     *
     * @param  array  $array
     * @return bool
     */
    public static function isAssoc(array $array)
    {
        $keys = array_keys($array);
    
        return array_keys($keys) !== $keys;
    }
    

    资料来源: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php

        16
  •  4
  •   c9s    10 年前

    通过使用 xarray PHP扩展

    您可以非常快地完成此操作(在php 5.6中大约快30倍):

    if (array_is_indexed($array)) {  }
    

    或:

    if (array_is_assoc($array)) {  }
    
        17
  •  3
  •   Champ    9 年前

    我的解决方案:

    function isAssociative(array $array)
    {
        return array_keys(array_merge($array)) !== range(0, count($array) - 1);
    }
    

    array_merge 在单个数组上,将重新索引所有 integer 钥匙,但不是其他的。例如:

    array_merge([1 => 'One', 3 => 'Three', 'two' => 'Two', 6 => 'Six']);
    
    // This will returns [0 => 'One', 1 => 'Three', 'two' => 'Two', 2 => 'Six']
    

    因此,如果创建了一个列表(非关联数组) ['a', 'b', 'c'] 然后移除一个值 unset($a[1]) 然后 数组合并 从0开始重新索引列表。

        18
  •  2
  •   AL the X    14 年前

    我使用的方法如下:

    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

        19
  •  2
  •   KillEveryBody    13 年前
    <?php
    
    function is_list($array) {
        return array_keys($array) === range(0, count($array) - 1);
    }
    
    function is_assoc($array) {
        return count(array_filter(array_keys($array), 'is_string')) == count($array);
    }
    
    ?>
    

    这两个得分最高的例子都不能正确地处理数组,比如 $array = array('foo' => 'bar', 1)

        20
  •  2
  •   Gordon    13 年前

    这也行( demo ):

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

    请注意,此答案的主要目的是告知您 SplFixedArray 并且不鼓励您在这些测试中使用异常。

        21
  •  2
  •   David Farrell    12 年前

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

    下面我介绍了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;
    }
    
        22
  •  2
  •   cloudfeet    12 年前

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

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

    与其检查这些键是否都是数字的,不如遍历 有一个数字数组,并确保它们存在。

        23
  •  2
  •   Kat Lim Ruiz    10 年前

    这是解决办法吗?

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

    警告很明显是数组光标被重置了,但我想说的是,可能在数组被遍历或使用之前就已经使用了函数。

        24
  •  2
  •   TylerY86    6 年前

    在进行了一些本地基准测试、调试、编译器探测、分析和滥用3v4l.org在更多版本之间进行基准测试之后(是的,我收到了停止的警告),并且 和我能找到的每一种变化作比较…

    我给你一个有机衍生的 最佳平均最坏情况 关联数组测试函数 最差的 大致与所有其他一般情况相同或更好。

    /**
     * Tests if an array is an associative array.
     *
     * @param array $array An array to test.
     * @return boolean True if the array is associative, otherwise false.
     */
    function is_assoc(array &$arr) {
        // don't try to check non-arrays or empty arrays
        if (FALSE === is_array($arr) || 0 === ($l = count($arr))) {
            return false;
        }
    
        // shortcut by guessing at the beginning
        reset($arr);
        if (key($arr) !== 0) {
            return true;
        }
    
        // shortcut by guessing at the end
        end($arr);
        if (key($arr) !== $l-1) {
            return true;
        }
    
        // rely on php to optimize test by reference or fast compare
        return array_values($arr) !== $arr;
    }
    

    https://3v4l.org/rkieX :

    <?php
    
    // array_values
    function method_1(Array &$arr) {
        return $arr === array_values($arr);
    }
    
    // method_2 was DQ; did not actually work
    
    // array_keys
    function method_3(Array &$arr) {
        return array_keys($arr) === range(0, count($arr) - 1);
    }
    
    // foreach
    function method_4(Array &$arr) {
        $idx = 0;
        foreach( $arr as $key => $val ){
            if( $key !== $idx )
                return FALSE;
            ++$idx;
        }
        return TRUE;
    }
    
    // guessing
    function method_5(Array &$arr) {
        global $METHOD_5_KEY;
        $i = 0;
        $l = count($arr)-1;
    
        end($arr);
        if ( key($arr) !== $l )
            return FALSE;
    
        reset($arr);
        do {
            if ( $i !== key($arr) )
                return FALSE;
            ++$i;
            next($arr);
        } while ($i < $l);
        return TRUE;
    }
    
    // naieve
    function method_6(Array &$arr) {
        $i = 0;
        $l = count($arr);
        do {
            if ( NULL === @$arr[$i] )
                return FALSE;
            ++$i;
        } while ($i < $l);
        return TRUE;
    }
    
    // deep reference reliance
    function method_7(Array &$arr) {
        return array_keys(array_values($arr)) === array_keys($arr);
    }
    
    
    // organic (guessing + array_values)
    function method_8(Array &$arr) {
        reset($arr);
        if ( key($arr) !== 0 )
            return FALSE;
    
        end($arr);
        if ( key($arr) !== count($arr)-1 )
            return FALSE;
    
        return array_values($arr) === $arr;
    }
    
    function benchmark(Array &$methods, Array &$target, $expected){    
        foreach($methods as $method){
            $start = microtime(true);
            for ($i = 0; $i < 2000; ++$i) {
                //$dummy = call_user_func($method, $target);
                if ( $method($target) !== $expected ) {
                    echo "Method $method is disqualified for returning an incorrect result.\n";
                    unset($methods[array_search($method,$methods,true)]);
                    $i = 0;
                    break;
                }
            }
            if ( $i != 0 ) {
                $end = microtime(true);
                echo "Time taken with $method = ".round(($end-$start)*1000.0,3)."ms\n";
            }
        }
    }
    
    
    
    $true_targets = [
        'Giant array' => range(0, 500),
        'Tiny array' => range(0, 20),
    ];
    
    
    $g = range(0,10);
    unset($g[0]);
    
    $false_targets = [
        'Large array 1' => range(0, 100) + ['a'=>'a'] + range(101, 200),
        'Large array 2' => ['a'=>'a'] + range(0, 200),
        'Tiny array' => range(0, 10) + ['a'=>'a'] + range(11, 20),
        'Gotcha array' => $g,
    ];
    
    $methods = [
        'method_1',
        'method_3',
        'method_4',
        'method_5',
        'method_6',
        'method_7',
        'method_8'
    ];
    
    
    foreach($false_targets as $targetName => $target){
        echo "==== Benchmark using $targetName expecing FALSE ====\n";
        benchmark($methods, $target, false);
        echo "\n";
    }
    foreach($true_targets as $targetName => $target){
        echo "==== Benchmark using $targetName expecting TRUE ====\n";
        benchmark($methods, $target, true);
        echo "\n";
    }
    
        25
  •  1
  •   lazycommit    11 年前

    再快一点 source . 适合的编码 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__)
            );
        }
    }
    
        26
  •  1
  •   nonsensei    9 年前

    已经给出了答案,但关于绩效的虚假信息太多了。 我编写了这个小的基准脚本,它表明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
    
        27
  •  0
  •   Daren Thomas    17 年前

    除非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 :)
    

    但是为什么要麻烦呢?假设数组是您期望的类型。如果不是的话,它会在你的脸上爆炸-这是动态编程为你!测试你的代码,一切都会好起来…

        28
  •  0
  •   philroy    16 年前

    我比较了数组的键和数组的array_values()结果的键之间的差异,后者始终是一个带整数索引的数组。如果键相同,则不是关联数组。

    function isHash($array) {
        if (!is_array($array)) return false;
        $diff = array_diff_assoc($array, array_values($array));
        return (empty($diff)) ? false : true;
    }
    
        29
  •  0
  •   Jason McCarrell    14 年前

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

    <?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
    ?>
    
        30
  •  0
  •   Selim Acar    13 年前

    在我看来,如果数组的任何键不是整数,例如浮点数和空字符串“”,则该数组应被接受为关联数组。

    此外,非序列整数也必须被视为类似于(0,2,4,6)的关联整数,因为这些类型的数组不能通过这种方式与for循环一起使用:

    $n =count($arr);
    for($i=0,$i<$n;$i++) 
    

    下面函数的第二部分检查键是否被索引。它也适用于负值的键。例如(-1,0,1,2,3,4,5)

    count() = 7 , max = 5, min=-1
    
    
    
    if( 7 == (5-(-1)+1 ) // true
        return false; // array not associative
    
    
    /** 
     * isAssoc Checks if an array is associative
     * @param $arr reference to the array to be checked
     * @return bool 
     */     
    function IsAssoc(&$arr){
        $keys= array_keys($arr);
        foreach($keys as $key){
            if (!is_integer($key))
                return true;
        }
        // if all keys are integer then check if they are indexed
        if(count($arr) == (max($keys)-min($keys)+1))
            return false;
        else
            return true;
    }
    
    推荐文章