PHP将所有数组视为关联的,因此没有任何内置函数.任何人都可以推荐一种相当有效的方法来检查数组是否只包含数字键?
基本上,我希望能够区分这个:
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
Run Code Online (Sandbox Code Playgroud)
还有这个:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
Run Code Online (Sandbox Code Playgroud)
Gre*_*reg 587
你问过两个不完全相同的问题:
考虑一下您实际需要的这些行为.(这可能是为了你的目的.)
第一个问题(简单地检查所有键都是数字)由kurO船长很好地回答.
对于第二个问题(检查数组是否为零索引和顺序),您可以使用以下函数:
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
Run Code Online (Sandbox Code Playgroud)
Cap*_*urO 424
仅检查数组是否具有非整数键(而不是数组是顺序索引还是零索引):
function has_string_keys(array $array) {
return count(array_filter(array_keys($array), 'is_string')) > 0;
}
Run Code Online (Sandbox Code Playgroud)
如果至少有一个字符串键,$array则将其视为关联数组.
Dav*_*all 128
当然这是一个更好的选择.
<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;
Run Code Online (Sandbox Code Playgroud)
squ*_*rel 77
这个问题中的许多评论者都不理解数组如何在PHP中工作.从阵列文档:
键可以是整数或字符串.如果一个键是整数的标准表示,它将被解释为这样(即"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);
Run Code Online (Sandbox Code Playgroud)
这是因为当当前数组位置无效时,key()返回NULL,而NULL永远不能是有效键(如果尝试使用NULL作为数组键,它会被静默转换为"").
Muh*_*kur 53
PHP 8.1 添加了一个内置函数来确定数组是否是具有这些语义的列表。函数是array_is_list:
$list = ["a", "b", "c"];
array_is_list($list); // true
$notAList = [1 => "a", 2 => "b", 3 => "c"];
array_is_list($notAList); // false
$alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];
array_is_list($alsoNotAList); // false
Run Code Online (Sandbox Code Playgroud)
请注意,此函数返回true空数组。
array_is_list([]); // true
Run Code Online (Sandbox Code Playgroud)
Pan*_*ang 38
如OP所述:
PHP将所有数组视为关联的
编写一个检查数组是否是关联的函数是不太明智的(恕我直言).首先要说的是:PHP数组中的键是什么?:
该键可以是一个整数或字符串.
这意味着有3种可能的情况:
我们可以使用以下功能检查每个案例.
注意:对于空数组,此函数也返回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);
}
Run Code Online (Sandbox Code Playgroud)
注意:对于空数组,此函数也返回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);
}
Run Code Online (Sandbox Code Playgroud)
注意:对于空数组,此函数也返回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;
}
Run Code Online (Sandbox Code Playgroud)
它遵循:
现在,对于一个我们都习以为常的"真正"数组,意思是:
我们可以查看以下功能.
注意:对于空数组,此函数也返回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);
}
Run Code Online (Sandbox Code Playgroud)
这些数组的键是整数:
array(0 => "b");
array(13 => "b");
array(-13 => "b"); // Negative integers are also integers.
array(0x1A => "b"); // Hexadecimal notation.
Run Code Online (Sandbox Code Playgroud)
这些数组的键是字符串:
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!
Run Code Online (Sandbox Code Playgroud)
如果你认为键入array("13" => "b")是一个字符串,那你错了.来自这里的文档:
包含有效整数的字符串将强制转换为整数类型.例如,键"8"实际上将存储在8下.另一方面,"08"将不会被转换,因为它不是有效的十进制整数.
例如,这些数组的键是整数:
array("13" => "b");
array("-13" => "b"); // Negative, ok.
Run Code Online (Sandbox Code Playgroud)
但这些数组的关键是字符串:
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.
Run Code Online (Sandbox Code Playgroud)
根据文件,更重要的是,
整数的大小取决于平台,尽管最大值约为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.
Run Code Online (Sandbox Code Playgroud)
更糟的是,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"
}
Run Code Online (Sandbox Code Playgroud)
但是在这个关于codepad(PHP 5.2.5)的现场演示中,同样的表达式给出了
array(1) {
["2147483647"]=>
string(1) "b"
}
Run Code Online (Sandbox Code Playgroud)
因此,密钥是一个环境中的整数,而另一个环境中的字符串,即使2147483647是有效的带符号32位整数.
Ali*_*xel 34
速度明智的:
function isAssoc($array)
{
return ($array !== array_values($array));
}
Run Code Online (Sandbox Code Playgroud)
内存明智的:
function isAssoc($array)
{
$array = array_keys($array); return ($array !== array_keys($array));
}
Run Code Online (Sandbox Code Playgroud)
小智 20
实际上最有效的方法是:
function is_assoc($array){
$keys = array_keys($array);
return $keys !== array_keys($keys);
}
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为它将键(对于顺序数组总是为0,1,2等)与键的键(总是为0,1,2等)进行比较.
dsi*_*ims 20
function checkAssoc($array){
return ctype_digit( implode('', array_keys($array) ) );
}
Run Code Online (Sandbox Code Playgroud)
pod*_*son 17
我已经使用了两个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;
}
Run Code Online (Sandbox Code Playgroud)
另请注意,如果您不关心将稀疏数组与关联数组区分开来,则只需'assoc'从两个if块返回即可.
最后,虽然这看起来不像本页面上的许多"解决方案"那么"优雅",但实际上它的效率要高得多.几乎任何关联数组都会立即被检测到.只有索引数组才能得到详尽的检查,上面列出的方法不仅详尽地检查了索引数组,而且还复制了它们.
小智 13
我认为以下两个函数是检查"数组是关联还是数字"的最佳方法.由于"数字"可能仅表示数字键或仅表示顺序数字键,因此下面列出了两个检查任一条件的函数:
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));
}
Run Code Online (Sandbox Code Playgroud)
第一个函数检查每个键是否为整数值.第二个函数检查每个键是否为整数值,另外检查所有键是否从$ base开始是连续的,默认为0,因此如果您不需要指定另一个基值,则可以省略.如果读指针移过数组末尾,那么key($ my_array)返回null,这就是for循环的结束,如果所有键都是整数,则使for循环后的语句返回true.如果不是,则循环过早结束,因为键的类型为string,而for循环后的语句将返回false.后一个函数在每次比较后另外添加一个$ base,以便能够检查下一个键是否具有正确的值.严格比较使它还检查键是否为整数类型.当省略$ base或者确保仅使用整数调用时,可以省略for循环第一部分中的$ base =(int)$ base部分.但是因为我不能确定每个人,所以我把它留了进去.无论如何,该声明只执行一次.我认为这些是最有效的解决方案:
请记住,数组键只能是整数或字符串,严格的数字字符串(如"1"(但不是"01"))将转换为整数.除了计算是否希望数组是顺序的,除了计算之外,检查整数键的唯一需要的操作是什么.当然,如果is_indexed_array返回false,则可以将该数组视为关联数组.我说'看',因为事实上他们都是.
Dip*_*mar 11
/**
* Determines if an array is associative.
* @param array $array
* @return bool
*/
function isAssoc(array $array)
{
$keys = array_keys($array);
return array_keys($keys) !== $keys;
}
Run Code Online (Sandbox Code Playgroud)
这个功能可以处理:
这个想法很简单:如果其中一个键不是整数,则它是关联数组,否则它是顺序的.
function is_asso($a){
foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
return FALSE;
}
Run Code Online (Sandbox Code Playgroud)
我注意到这个问题有两个流行的方法:一个使用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";
Run Code Online (Sandbox Code Playgroud)
CentOS上PHP 5.2程序的输出如下:
方法#1的
时间= 10.745ms 方法#2的时间= 18.239ms
PHP 5.3的输出产生了类似的结果.显然使用array_values()速度要快得多.
小智 7
解决这个问题的一种方法是搭载json_encode,它已经有了自己的内部方法来区分关联数组和索引数组,以便输出正确的JSON.
您可以通过检查编码后返回的第一个字符是{(关联数组)还是[(索引数组)来执行此操作.
// Too short :)
function is_assoc($arr) {
ksort($arr);
return json_encode($arr)[0] === '{';
}
Run Code Online (Sandbox Code Playgroud)
已有很多答案,但这里是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;
}
Run Code Online (Sandbox Code Playgroud)
资料来源:https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php
function array_is_assoc(array $a) {
$i = 0;
foreach ($a as $k => $v) {
if ($k !== $i++) {
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
快速,简洁,内存高效.没有昂贵的比较,函数调用或数组复制.
大多数答案具有次优的时间/空间复杂度或正在改变语义。因此,这是另一个具有最快且功能最正确的解决方案的答案:
function is_sequential_array(Array &$a) {
$n = count($a);
for($i=0; $i<$n; $i++) {
if(!array_key_exists($i, $a)) {
return false;
}
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
与其他答案相比,此答案具有以下优势:
O(1)(这里的许多答案都使用O(n)空间!)array_key_exists而不是isset(记住,isset另外检查“不为空”,从而改变语义)O(n)(这里的许多答案的最佳情况时间复杂度为O(n))