如何检查 PHP 数组是关联的还是顺序的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/173400/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 21:46:54  来源:igfitidea点击:

How to check if PHP array is associative or sequential?

phparrays

提问by Wilco

PHP treats all arrays as associative, so there aren't any built in functions. Can anyone recommend a fairly efficient way to check if an array contains only numeric keys?

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

Basically, I want to be able to differentiate between this:

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

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

and this:

和这个:

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

采纳答案by Greg

You have asked two questions that are not quite equivalent:

你问了两个不太对等的问题:

  • Firstly, how to determine whether an array has only numeric keys
  • Secondly, how to determine whether an array has sequentialnumeric keys, starting from 0
  • 一、如何判断一个数组是否只有数字键
  • 其次,如何判断一个数组是否有连续的数字键,从0开始

Consider which of these behaviours you actually need. (It may be that either will do for your purposes.)

考虑您实际需要这些行为中的哪些。(这可能是为了您的目的。)

The first question (simply checking that all keys are numeric) is answered well by Captain kurO.

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

For the second question (checking whether the array is zero-indexed and sequential), you can use the following function:

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

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

回答by Captain kurO

To merely check whether the array has non-integer keys (not whether the array is sequentially-indexed or zero-indexed):

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

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

If there is at least one string key, $arraywill be regarded as an associative array.

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

回答by Dave Marshall

Surely this is a better alternative.

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

<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;

回答by squirrel

Many commenters in this question don't understand how arrays work in PHP. From the array documentation:

这个问题的许多评论者不了解数组在 PHP 中的工作原理。从阵列文档

A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. "8" will be interpreted as 8, while "08" will be interpreted as "08"). Floats in key are truncated to integer. The indexed and associative array types are the same type in PHP, which can both contain integer and string indices.

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

In other words, there is no such thing as an array key of "8" because it will always be (silently) converted to the integer 8. So trying to differentiate between integers and numeric strings is unnecessary.

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

If you want the most efficient way to check an array for non-integer keys without making a copy of part of the array (like array_keys() does) or all of it (like foreach does):

如果您想要最有效的方法来检查数组的非整数键而不复制数组的一部分(如 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);

This works because key() returns NULL when the current array position is invalid and NULL can never be a valid key (if you try to use NULL as an array key it gets silently converted to "").

这是有效的,因为当当前数组位置无效时,key() 返回 NULL 并且 NULL 永远不会是有效的键(如果您尝试使用 NULL 作为数组键,它会被静默转换为“”)。

回答by Pang

As stated by the OP:

正如OP 所说

PHP treats all arrays as associative

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

it is not quite sensible (IMHO) to write a function that checks if an array is associative. So first thing first: what is a key in a PHP array?:

编写一个检查数组是否关联的函数并不是很明智(恕我直言)。所以第一件事PHP 数组中的键是什么?:

The keycan either be an integeror a string.

可以是一个整数字符串

That means there are 3 possible cases:

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

  • Case 1. all keys are numeric/ integers.
  • Case 2. all keys are strings.
  • Case 3. some keys are strings, some keys are numeric/ integers.
  • 案例 1. 所有键都是数字/整数
  • 情况 2. 所有的键都是字符串
  • 情况 3. 有些键是字符串,有些键是数字/整数

We can check each case with the following functions.

我们可以使用以下函数检查每种情况。

Case 1: all keys are numeric/ integers.

情况 1:所有键都是数字/整数

Note: This function returns truefor empty arrays too.

注意此函数对空数组也返回true

//! 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);
}

Case 2: all keys are strings.

情况 2:所有键都是strings

Note: This function returns truefor empty arrays too.

注意此函数对空数组也返回true

//! 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);
}

Case 3. some keys are strings, some keys are numeric/ integers.

情况 3. 有些键是字符串,有些键是数字/整数

Note: This function returns truefor empty arrays too.

注意此函数对空数组也返回true

//! 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;
}

It follows that:

它遵循:



Now, for an array to be a "genuine" arraythat we are all accustomed to, meaning:

现在,要使数组成为我们都习惯的“真正”数组,这意味着:

  • Its keys are all numeric/ integers.
  • Its keys are sequential(i.e. increasing by step 1).
  • Its keys start from zero.
  • 它的键都是数字/整数
  • 它的键是连续的(即按步骤 1 递增)。
  • 它的键从零开始

We can check with the following function.

我们可以使用以下函数进行检查。

Case 3a. keys are numeric/ integers, sequential, and zero-based.

情况 3a。键是数字/整数顺序从零开始

Note: This function returns truefor empty arrays too.

注意此函数对空数组也返回true

//! 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);
}

Caveats / Pitfalls (or, even more peculiar facts about array keys in PHP)

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

Integer keys

整数键

The keys for these arrays are integers:

这些数组的键是整数

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

String keys

字符串键

The keys for these arrays are strings:

这些数组的键是字符串

array("fish and chips" => "b");
array("" => "b");                                   // An empty string is also a string.
array("[email protected]" => "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!

Integer keys that look like strings

看起来像字符串的整数键

If you think the key in array("13" => "b")is a string, you are wrong. From the doc here:

如果您认为输入的键array("13" => "b")字符串,那您就错了。从这里的文档:

Strings containing valid integers will be cast to the integer type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer.

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

For example, the key for these arrays are integers:

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

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

But the key for these arrays are strings:

但是这些数组的关键是字符串

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.

What's more, according to the doc,

更重要的是,根据文档

The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). 64-bit platforms usually have a maximum value of about 9E18, except for Windows, which is always 32 bit. PHP does not support unsigned integers.

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

So the key for this array may or may notbe an integer- it depends on your platform.

因此,对于这个阵列的关键可能或不可能整数-这取决于你的平台上。

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

Even worse, PHP tends to be buggyif the integer is near the 231= 2,147,483,648 boundary (see bug 51430, bug 52899). For example, on my local environment (PHP 5.3.8 on XAMPP 1.7.7 on Windows 7), var_dump(array("2147483647" => "b"))gives

更糟的是,PHP趋向于如果整数是2的附近31= 2,147,483,648边界(参见错误51430错误52899)。例如,在我的本地环境(Windows 7 上 XAMPP 1.7.7 上的 PHP 5.3.8)中,var_dump(array("2147483647" => "b"))给出

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

but on this live demo on codepad(PHP 5.2.5), the same expression gives

但是在键盘(PHP 5.2.5)上的这个现场演示中,相同的表达式给出

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

So the key is an integerin one environment but a stringin another, even though 2147483647is a valid signed 32-bit integer.

所以密钥在一个环境中是一个整数,而在另一个环境中是一个字符串,即使2147483647是一个有效的有符号 32 位整数

回答by Alix Axel

Speed-wise:

速度方面:

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

Memory-wise:

记忆方面:

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

回答by Alix Axel

Actually the most efficient way is thus:

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

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

This works because it compares the keys (which for a sequential array are always 0,1,2 etc) to the keys of the keys (which will alwaysbe 0,1,2 etc).

这是有效的,因为它将键(对于顺序数组始终为 0、1、2 等)与键的键(始终为 0、1、2 等)进行比较。

回答by dsims

function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}

回答by podperson

I've used both array_keys($obj) !== range(0, count($obj) - 1)and array_values($arr) !== $arr(which are duals of each other, although the second is cheaper than the first) but both fail for very large arrays.

我已经使用了array_keys($obj) !== range(0, count($obj) - 1)array_values($arr) !== $arr(它们是彼此的对偶,虽然第二个比第一个便宜)但是对于非常大的阵列都失败了。

This is because array_keysand array_valuesare both very costly operations (since they build a whole new array of size roughly that of the original).

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

The following function is more robust than the methods provided above:

以下函数比上面提供的方法更健壮:

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;
}

Also note that if you don't care to differentiate sparse arrays from associative arrays you can simply return 'assoc'from both ifblocks.

另请注意,如果您不关心将稀疏数组与关联数组区分开来,则可以简单地'assoc'从两个if块中返回。

Finally, while this might seem much less "elegant" than a lot of "solutions" on this page, in practice it is vastly more efficient. Almost any associative array will be detected instantly. Only indexed arrays will get checked exhaustively, and the methods outlined above not only check indexed arrays exhaustively, they duplicate them.

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

回答by Niels Ockeloen

I think the following two functions are the best way to go for checking 'if an array is associative or numeric'. Since 'numeric' could mean only numeric keys or only sequential numeric keys, two functions are listed below that check either condition:

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

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));
}

The first function checks if each key is an integer value. The second function checks if each key is an integer value and in addition checks if all keys are sequential starting at $base, which defaults to 0 and thus can be omitted if you do not need to specify another base value. key($my_array) returns null if the read pointer is moved past the end of the array, which is what ends the for loop and makes the statement after the for loop return true if all keys were integer. If not, the loop ends prematurely because a key is of type string, and the statement after the for loop will return false. The latter function in addition adds one to $base after each compare, to be able to check if the next key is of the correct value. The strict compare makes it also check if the key is of type integer. The $base = (int) $base part in the first section of the for loop can be left out when $base is omitted or if you make sure it is only called using an integer. But since I can't be sure for everybody, I left it in. The statement is executed only once, anyway. I think these are the most efficient solutions:

第一个函数检查每个键是否为整数值。第二个函数检查每个键是否为整数值,此外检查所有键是否从 $base 开始是连续的,$base 默认为 0,因此如果您不需要指定另一个基值,则可以省略。如果读取指针移过数组末尾,key($my_array) 将返回 null,这将结束 for 循环并使 for 循环之后的语句在所有键都是整数时返回 true。如果不是,循环会提前结束,因为键是字符串类型,for 循环之后的语句将返回 false。后一个函数在每次比较后都会向 $base 添加一个,以便能够检查下一个键是否具有正确的值。严格比较使其还检查键是否为整数类型。当 $base 被省略或者您确保只使用整数调用它时,可以省略 for 循环第一部分中的 $base = (int) $base 部分。但是因为我不能确定每个人,所以我把它留了下来。无论如何,该语句只执行一次。我认为这些是最有效的解决方案:

  • Memory wise: No copying of data or key ranges. Doing an array_values or array_keys may seem shorter (less code) but keep in mind what goes on in the background once you make that call. Yes there are more (visible) statements than in some other solutions, but that is not what counts, is it?
  • Time wise: Besides the fact that copying/extracting data and/or keys also takes time, this solution is more efficient than doing a foreach. Again a foreach may seem more efficient to some because it is shorter in notation, but in the background foreach also calls reset, key and next to do it's looping. But in addition it also calls valid to check the end condition, which is avoided here due to the combination with the integer check.
  • 内存明智:不复制数据或键范围。执行 array_values 或 array_keys 可能看起来更短(更少的代码),但请记住,一旦您拨打该电话,后台会发生什么。是的,与其他一些解决方案相比,有更多(可见的)语句,但这并不重要,是吗?
  • 时间明智:除了复制/提取数据和/或密钥也需要时间这一事实之外,此解决方案比执行 foreach 更有效。同样,foreach 对某些人来说似乎更有效,因为它的符号较短,但在后台 foreach 也调用 reset、key 和 next 来执行循环。但除此之外它还会调用valid 来检查结束条件,这里由于结合了整数检查而避免使用。

Remember that an array key can only be an integer or a string, and a strictly numeric string such as "1" (but not "01") will be translated into an integer. Which is what makes checking for an integer key the only needed operation besides counting if you want the array to be sequential. Naturally, if is_indexed_array returns false the array can be seen as associative. I say 'seen', because in fact they all are.

请记住,数组键只能是整数或字符串,而严格的数字字符串如“1”(但不是“01”)将被转换为整数。如果您希望数组是连续的,那么除了计数之外,检查整数键是唯一需要的操作。自然地,如果 is_indexed_array 返回 false,则数组可以被视为关联的。我说“见过”,因为事实上它们都是。