PHP将所有数组视为关联的,因此没有任何内置函数。任何人都可以推荐一种相当有效的方法来检查一个数组是否只包含数字键吗?
基本上,我希望能够区分这个:
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
和此:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
答案 0 :(得分:553)
您提出了两个不完全相同的问题:
考虑您实际需要哪些行为。 (这可能是为了你的目的。)
第一个问题(只是检查所有键都是数字)是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
答案 1 :(得分:415)
仅检查数组是否具有非整数键(不是数组是顺序索引还是零索引):
function has_string_keys(array $array) {
return count(array_filter(array_keys($array), 'is_string')) > 0;
}
如果至少有一个字符串键,$array
将被视为关联数组。
答案 2 :(得分:127)
当然,这是一个更好的选择。
<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;
答案 3 :(得分:73)
此问题中的许多评论者都不了解数组如何在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);
这是因为当当前数组位置无效时,key()返回NULL,而NULL永远不能是有效键(如果你尝试使用NULL作为数组键,它会被静默转换为“”)。
答案 4 :(得分:38)
PHP将所有数组视为关联
编写一个检查数组是否为 associative 的函数是不太明智的(恕我直言)。首先要做的是:what is a key in a PHP array?:
键可以是整数或字符串。
这意味着有三种可能的情况:
我们可以使用以下功能检查每个案例。
注意:此函数也会为空数组返回 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);
}
注意:此函数也会为空数组返回 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);
}
注意:此函数也会为空数组返回 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;
}
由此得出:
现在,对于一个我们都习以为常的“正版”数组的数组,意思是:
我们可以查看以下功能。
注意:此函数也会为空数组返回 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);
}
这些数组的键是 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.
更糟糕的是,如果整数接近2 31 = 2,147,483,648边界,则PHP往往是 buggy (参见bug 51430,bug 52899) 。例如,在我的本地环境(Windows 7上的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位整数
答案 5 :(得分:34)
<强>速度逐强>
function isAssoc($array)
{
return ($array !== array_values($array));
}
<强>内存明智:强>
function isAssoc($array)
{
$array = array_keys($array); return ($array !== array_keys($array));
}
答案 6 :(得分:19)
实际上最有效的方式是:
function is_assoc($array){
$keys = array_keys($array);
return $keys !== array_keys($keys);
}
这是有效的,因为它将键(对于顺序数组总是为0,1,2等)与键的键(总是为0,1,2等)进行比较
答案 7 :(得分:18)
function checkAssoc($array){
return ctype_digit( implode('', array_keys($array) ) );
}
答案 8 :(得分: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;
}
另请注意,如果您不想将稀疏数组与关联数组区分开来,则只需从'assoc'
块中返回if
。
最后,虽然这看起来不像本页面上的许多“解决方案”那么“优雅”,但实际上它的效率要高得多。几乎任何关联数组都会立即被检测到。只有索引数组才能得到详尽的检查,上面列出的方法不仅可以详尽地检查索引数组,而且还可以复制它们。
答案 9 :(得分: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));
}
第一个函数检查每个键是否为整数值。第二个函数检查每个键是否为整数值,另外检查所有键是否从$ base开始是连续的,默认为0,因此如果您不需要指定另一个基值,则可以省略。如果读指针移过数组末尾,那么key($ my_array)返回null,这就是for循环的结束,如果所有键都是整数,则使for循环后的语句返回true。如果不是,则循环过早结束,因为键的类型为string,而for循环后的语句将返回false。后一个函数在每次比较后另外添加一个$ base,以便能够检查下一个键是否具有正确的值。严格比较使它还检查键是否为整数类型。当省略$ base或者确保仅使用整数调用时,可以省略for循环第一部分中的$ base =(int)$ base部分。但是因为我无法确定每个人,所以我把它留了进去。无论如何,该声明只执行一次。我认为这些是最有效的解决方案:
请记住,数组键只能是整数或字符串,严格的数字字符串(如“1”(但不是“01”))将转换为整数。除了计算是否希望数组是顺序的,除了计算之外,检查整数键的唯一需要的操作是什么。当然,如果is_indexed_array返回false,则可以将该数组视为关联数组。我说'看过',因为事实上它们都是。“
答案 10 :(得分:7)
我注意到这个问题有两种流行的方法:一种使用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上的输出产生了类似的结果。显然使用array_values()
要快得多。
答案 11 :(得分:7)
此功能可以处理:
这个想法很简单:如果其中一个键不是整数,那么它是关联数组,否则它是顺序的。
function is_asso($a){
foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
return FALSE;
}
答案 12 :(得分:6)
解决这个问题的一种方法是搭载json_encode
,它已经有了自己的内部方法来区分关联数组和索引数组,以便输出正确的JSON。
您可以通过检查编码后返回的第一个字符是{
(关联数组)还是[
(索引数组)来执行此操作。
// Too short :)
function is_assoc($arr) {
ksort($arr);
return json_encode($arr)[0] === '{';
}
答案 13 :(得分:5)
已经有很多答案,但这里是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
答案 14 :(得分:5)
function array_is_assoc(array $a) {
$i = 0;
foreach ($a as $k => $v) {
if ($k !== $i++) {
return true;
}
}
return false;
}
快速,简洁,内存高效。没有昂贵的比较,函数调用或数组复制。
答案 15 :(得分:4)
使用xarray PHP扩展
您可以非常快速地完成此任务(在PHP 5.6中快30倍以上):
if (array_is_indexed($array)) { }
或者:
if (array_is_assoc($array)) { }
答案 16 :(得分:3)
/**
* Determines if an array is associative.
* @param array $array
* @return bool
*/
function isAssoc(array $array)
{
$keys = array_keys($array);
return array_keys($keys) !== $keys;
}
答案 17 :(得分:3)
我的解决方案:
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])
,然后调用array_merge
,从0开始重新编制索引。
答案 18 :(得分:2)
这可能是解决方案吗?
public static function isArrayAssociative(array $array) {
reset($array);
return !is_int(key($array));
}
警告显然是数组游标被重置但是我可能会说在遍历或使用数组之前可能会使用该函数。
答案 19 :(得分:2)
经过一些本地基准测试,调试,编译器探测,分析和滥用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;
}
<?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";
}
答案 20 :(得分:2)
我认为标量数组的定义因应用程序而异。也就是说,某些应用程序需要更严格地了解什么是标量数组,而某些应用程序需要更宽松的感觉。
下面我介绍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;
}
答案 21 :(得分:2)
这也可以(demo):
function array_has_numeric_keys_only(array $array)
{
try {
SplFixedArray::fromArray($array, true);
} catch (InvalidArgumentException $e) {
return false;
}
return true;
}
请注意,这个答案的要点是告知您SplFixedArray
的存在,而不是鼓励您使用例外来进行这类测试。
答案 22 :(得分:2)
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
答案 23 :(得分:2)
<?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)
答案 24 :(得分:2)
我知道添加这个庞大队列的答案有点无意义,但这是一个可读的O(n)解决方案,不需要复制任何值:
function isNumericArray($array) {
$count = count($array);
for ($i = 0; $i < $count; $i++) {
if (!isset($array[$i])) {
return FALSE;
}
}
return TRUE;
}
不是检查键以查看它们是否都是数字键,而是迭代将存在于数字数组中的键并确保它们存在。
答案 25 :(得分:2)
这是我使用的方法:
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
答案 26 :(得分:1)
免责声明:以下方法是从其他答案中复制粘贴的
==== 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
结果:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"/>
</LinearLayout>
答案 27 :(得分:1)
有时候,您只能检查第一个数组的Key是否为0。
$isSequential = array_keys($arr)[0] === 0
,或更快速但更详细的版本:
reset($arr); $isSequential = key($arr) === 0
答案 28 :(得分:1)
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__)
);
}
}
答案 29 :(得分:0)
或者您可以只使用此:
Arr::isAssoc($array)
它将检查数组是否包含任何非数字键或:
Arr:isAssoc($array, true)
检查数组是否严格顺序(包含自动生成的int键 0 到 n-1 )
使用this库。
答案 30 :(得分:0)
当涉及到php数组时,这个问题实际上是没有用的,因为考虑到php的本质,数组不必完全关联或建立索引,它可以结合使用,这是用户定义和分配值的方式。数组可以是两者的组合。参见下面的示例
$y= array(5);
$y["0x"]="n";
$y["vbg"]="12132";
$y[1] = "k";
var_dump($y); //this will output 4 element array
echo "</br>" .$y["0x"]."</br>".$y[0];
for($x=0;$x<sizeof($y);$x++){ // this will output all index elements & gives error after that
echo "</br> index elements ".$y[$x];
}
所以必须要问的正确问题是,数组中的所有元素是关联还是索引。如果您真的知道它只会是关联的或索引的,而不是这两者的组合,则只需使用此方法查找它是索引还是关联的数组即可。
function AssocTest(&$arr){
if(is_array($arr)){
reset($arr); // reset pointer to first element of array
if(gettype(key($arr)) == "string"){ //get the type(nature) of first element key
return true;
}else{
return false;
}
}else{
return false;
}
}
您可以将其用作常规功能
echo(AssocTest($y)? "Associative array": "Not an Associative array/ Not an array at all");
记住evan的一件重要事情是,您已经将数组初始化为关联数组,但是您给关联数组指定的名称只是数字,如果您没有显式给出字符串,则在被php读取时,它将被视为索引数组。名称。看看下面的例子。
$y["0"]="n";
$y["1"]="12132";
$y["22"] = "k";
//both will get the same output
echo "<br/> s0 ".$y["22"];
echo "<br/> s0 ".$y[22];
for($x=0;$x<count($y);$x++){
echo "<br/> arr ".$y[$x]; // this will output up to 2nd element and give an error after
}
因此,如果您需要确保数组的所有元素都被完全索引或建立关联,则别无选择,只能对所有元素进行校验,并按生成的索引数组检查每个元素键,因为许多这里的人。
function fullAssocTest(&$arr)
{
if(is_array($arr)){
return (array_keys($arr) !== range(0, count($arr) - 1));
}
}
它的编码较少,但是这确实是过程密集型工作,并且是不必要的工作。
答案 31 :(得分:0)
我想出了下一个方法:
function isSequential(array $list): bool
{
$i = 0;
$count = count($list);
while (array_key_exists($i, $list)) {
$i += 1;
if ($i === $count) {
return true;
}
}
return false;
}
var_dump(isSequential(array())); // false
var_dump(isSequential(array('a', 'b', 'c'))); // true
var_dump(isSequential(array("0" => 'a', "1" => 'b', "2" => 'c'))); // true
var_dump(isSequential(array("1" => 'a', "0" => 'b', "2" => 'c'))); // true
var_dump(isSequential(array("1a" => 'a', "0b" => 'b', "2c" => 'c'))); // false
var_dump(isSequential(array("a" => 'a', "b" => 'b', "c" => 'c'))); // false
*请注意,空数组不视为顺序数组,但是我认为这很好,因为空数组就像0一样-不管它的正负,它都是空的。
与上面列出的一些方法相比,这是该方法的优点:
array_values
不涉及复制-什么!?? 它确实涉及-如下所示)我使用了Artur Bodera提供的基准测试,在该基准测试中,我将其中一个数组更改为1M个元素(array_fill(0, 1000000, uniqid()), // big numeric array
)。
这是100次迭代的结果:
PHP 7.1.16 (cli) (built: Mar 31 2018 02:59:59) ( NTS )
Initial memory: 32.42 MB
Testing my_method (isset check) - 100 iterations
Total time: 2.57942 s
Total memory: 32.48 MB
Testing method3 (array_filter of keys) - 100 iterations
Total time: 5.10964 s
Total memory: 64.42 MB
Testing method1 (array_values check) - 100 iterations
Total time: 3.07591 s
Total memory: 64.42 MB
Testing method2 (array_keys comparison) - 100 iterations
Total time: 5.62937 s
Total memory: 96.43 MB
*方法根据其内存消耗进行排序
**我使用echo " Total memory: " . number_format(memory_get_peak_usage()/1024/1024, 2) . " MB\n";
来显示内存使用情况
答案 32 :(得分:0)
在我看来,如果一个数组的任何键不是整数,那么它应该被接受为关联的。浮点数和空字符串''。
同样,非序列整数必须被视为关联式(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;
}
答案 33 :(得分:0)
这里的许多解决方案优雅美观,但扩展性不佳,并且占用大量内存或CPU。从比较的两面来看,大多数使用此解决方案在内存中创建2个新数据点。阵列越大,使用的过程和内存就越难,而且时间越长,您就失去了短路评估的好处。我做了一些不同想法的测试。尽量避免使用array_key_exists,因为这样做代价高昂,并且还避免创建新的大型数据集进行比较。我觉得这是判断数组是否顺序的简单方法。
public function is_sequential( $arr = [] ){
if( !is_array( $arr ) || empty( $arr ) ) return false;
$i = 0;
$total = count( $arr );
foreach( $arr as $key => $value ) if( $key !== $i++ ) return false;
return true;
}
您在主数组上运行单个计数并存储单个整数。然后,您遍历数组并在迭代计数器时检查是否完全匹配。您应该从1开始计数。如果失败,它将短路,错误时将提高性能。
最初,我使用for循环并检查isset($ arr [$ i])来执行此操作,但这不会检测到需要array_key_exists的空键,并且众所周知,这是速度上最差的功能。>
通过foreach不断更新变量,以与迭代器一起检查,使其永远不会超过整数大小,让PHP使用它内置的内存优化,缓存和垃圾回收功能,使您的资源使用率非常低。
此外,我将争辩说,当您只需运行$ key => $ value并检查密钥时,在foreach中使用array_keys是愚蠢的。为什么要创建新的数据点?一旦抽象出阵列键,您将立即消耗更多的内存。
答案 34 :(得分:0)
大多数答案具有次佳的时间/空间复杂度或正在变化的语义。因此,这是最快和功能上最正确的解决方案的另一个答案:
function is_simple_array(Array &$a) {
$n = count($a);
for($i=0; $i<$n; $i++) {
if(!array_key_exists($i, $a)) {
return false;
}
}
return true;
}
此答案相对于其他答案具有以下优点:
O(1)
的空间复杂度(许多答案在这里使用O(n)
空间!)array_key_exists
代替isset
(请记住,isset
还会检查'is not null',从而改变语义)答案 35 :(得分:0)
对最受欢迎的答案进行修改 这需要更多的处理,但更准确。
<?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
?>
答案 36 :(得分:0)
我比较了数组的键和数组的array_values()结果的键之间的差异,它总是一个带整数索引的数组。如果键是相同的,它不是关联数组。
function isHash($array) {
if (!is_array($array)) return false;
$diff = array_diff_assoc($array, array_values($array));
return (empty($diff)) ? false : true;
}
答案 37 :(得分:0)
另一种方法。
function array_isassociative($array)
{
// Create new Array, Make it the same size as the input array
$compareArray = array_pad(array(), count($array), 0);
// Compare the two array_keys
return (count(array_diff_key($array, $compareArray))) ? true : false;
}
答案 38 :(得分:0)
function is_associative($arr) {
return (array_merge($arr) !== $arr || count(array_filter($arr, 'is_string', ARRAY_FILTER_USE_KEY)) > 0);
}
答案 39 :(得分:0)
除非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 :)
但为什么要这么麻烦?假设数组是您期望的类型。如果不是这样,它就会在你脸上爆炸 - 这是你的动态编程!测试你的代码,一切都会很好......
答案 40 :(得分:-1)
class addUserForm(forms.Form):
cluster = forms.ChoiceField(widget=forms.Select(attrs={ "id" : "id_cluster" }), choices=TABLEAU_ENVIRONMENTS)
privelege = forms.ChoiceField(widget=forms.Select(attrs={ "id" : "id_privelege" }), choices=ROLES)
user_id = forms.CharField(widget=forms.TextInput(attrs={ "id" : "id_user_id" }), label="User ID", max_length=10)
site = forms.CharField(widget=forms.Select(attrs={ "id" : "id_site" }))
•不使用回调,它比当前的领先答案快30%, 并可能提高内存效率。
•否定答案即可知道该数组是否应视为关联数组。
答案 41 :(得分:-1)
一种廉价而肮脏的方式就是这样检查:
isset($myArray[count($myArray) - 1])
...如果您的数组是这样的话,您可能会误报:
$myArray = array("1" => "apple", "b" => "banana");
更彻底的方法可能是检查键:
function arrayIsAssociative($myArray) {
foreach (array_keys($myArray) as $ind => $key) {
if (!is_numeric($key) || (isset($myArray[$ind + 1]) && $myArray[$ind + 1] != $key + 1)) {
return true;
}
}
return false;
}
// this will only return true if all the keys are numeric AND sequential, which
// is what you get when you define an array like this:
// array("a", "b", "c", "d", "e");
或
function arrayIsAssociative($myArray) {
$l = count($myArray);
for ($i = 0; $i < $l, ++$i) {
if (!isset($myArray[$i])) return true;
}
return false;
}
// this will return a false positive on an array like this:
$x = array(1 => "b", 0 => "a", 2 => "c", 4 => "e", 3 => "d");
答案 42 :(得分:-1)
我很惊讶没有人提到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
详细了解此功能here。
答案 43 :(得分:-1)
这是我的功能 -
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相关函数的另一种方式。与此处发布的其他解决方案相比,我还没有检查此解决方案在性能方面的表现。但它肯定帮助我解决了这个问题。希望这会有所帮助。
答案 44 :(得分:-1)
检查数组是否包含所有关键字。使用stdClass
&amp; get_object_vars ^):
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
$assoc_object = (object) $assocArray;
$isAssoc = (count($assocArray) === count (get_object_vars($assoc_object)));
var_dump($isAssoc); // true
为什么呢?功能get_object_vars
仅返回可访问的属性(请参阅有关将array
转换为object
here期间发生的更多信息)。然后,逻辑上:如果基本数组元素的数量等于对象的可访问属性的数量 - 所有键都是关联的。
很少有测试:
$assocArray = array('apple', 'orange', 'tomato', 'carrot');
$assoc_object = (object) $assocArray;
$isAssoc = (count($assocArray) === count (get_object_vars($assoc_object)));
var_dump($isAssoc); // false
//...
$assocArray = array( 0 => 'apple', 'orange', 'tomato', '4' => 'carrot');
$assoc_object = (object) $assocArray;
$isAssoc = (count($assocArray) === count (get_object_vars($assoc_object)));
var_dump($isAssoc); // false
//...
$assocArray = array('fruit1' => 'apple',
NULL => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
$assoc_object = (object) $assocArray;
$isAssoc = (count($assocArray) === count (get_object_vars($assoc_object)));
var_dump($isAssoc); //false
等
答案 45 :(得分:-1)
Mark Amery的改进
function isAssoc($arr)
{
// Is it set, is an array, not empty and keys are not sequentialy numeric from 0
return isset($arr) && is_array($arr) && count($arr)!=0 && array_keys($arr) !== range(0, count($arr) - 1);
}
这测试变量是否存在,是否为数组,如果它不是空数组,并且键不是从0开始的顺序。
查看数组是否是关联的
if (isAssoc($array)) ...
查看它是否为数字
if (!isAssoc($array)) ...
答案 46 :(得分:-1)
function is_array_assoc($foo) {
if (is_array($foo)) {
return (count(array_filter(array_keys($foo), 'is_string')) > 0);
}
return false;
}
答案 47 :(得分:-1)
实际上,我发现自己处于类似的情况,试图获取一个数组并将其解析为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 Escape Sequences和PCRE Syntax页面。
以下是我正在处理的示例数组:
案例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",
),
);
问题是filter
键是可变的。例如:
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>
...但是,如果我正在转换的数组就像案例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>
答案 48 :(得分:-1)
我的解决方案是获取如下数组的键,并检查键是否不是整数:
private function is_hash($array) {
foreach($array as $key => $value) {
return ! is_int($key);
}
return false;
}
获取如下所示的哈希数组的array_keys是错误的:
array_keys(array(
"abc" => "gfb",
"bdc" => "dbc"
)
);
将输出:
array(
0 => "abc",
1 => "bdc"
)
因此,将它与最高评级答案中提到的一系列数字进行比较并不是一个好主意。如果您尝试将键与范围进行比较,它总是会说它是一个哈希数组。
答案 49 :(得分:-1)
我几天前又遇到过这个问题,我想利用array_merge特殊属性:
如果输入数组具有相同的字符串键,则该键的后一个值将覆盖前一个。但是,如果数组包含数字键,则以后的值不会覆盖原始值,但会附加。带有数字键的输入数组中的值将使用从结果数组中的零开始的递增键重新编号。 那么为什么不使用:
function Is_Indexed_Arr($arr){
$arr_copy = $arr;
if((2*count($arr)) == count(array_merge($arr, $arr_copy))){
return 1;
}
return 0;
}
答案 50 :(得分:-2)
以简单的方式,您可以通过以下步骤检查数组是否关联
array_keys()
array_filter()
和来过滤掉数组中的非数字键
is_numeric()
上述步骤的功能如下。
function isAssociative(array $array)
{
return count(array_filter(array_keys($array), function($v){return is_numeric($v);})) !== count($array));
}
答案 51 :(得分:-2)
简单且性能友好的解决方案,仅检查第一个密钥。
function isAssoc($arr = NULL)
{
if ($arr && is_array($arr))
{
foreach ($arr as $key => $val)
{
if (is_numeric($key)) { return true; }
break;
}
}
return false;
}
答案 52 :(得分:-2)
检测关联数组(哈希数组)的最佳函数
<?php
function is_assoc($arr) { return (array_values($arr) !== $arr); }
?>
答案 53 :(得分:-2)
另一个尚未显示的变体,因为它根本不接受数字键,但我非常喜欢Greg的那个:
/* Returns true if $var associative array */
function is_associative_array( $array ) {
return is_array($array) && !is_numeric(implode('', array_keys($array)));
}
答案 54 :(得分:-2)
function isAssoc($arr)
{
$a = array_keys($arr);
for($i = 0, $t = count($a); $i < $t; $i++)
{
if($a[$i] != $i)
{
return false;
}
}
return true;
}
答案 55 :(得分:-2)
function is_assoc(array $array): bool
{
foreach ($array as $iValue) {
if (is_array($iValue)) {
return true;
}
}
return false;
}
$d= is_assoc(["id",2,3]);
var_dump($d);
答案 56 :(得分:-3)
我只使用key()函数。观察:
<?php
var_dump(key(array('hello'=>'world', 'hello'=>'world'))); //string(5) "hello"
var_dump(key(array('world', 'world'))); //int(0)
var_dump(key(array("0" => 'a', "1" => 'b', "2" => 'c'))); //int(0) who makes string sequetial keys anyway????
?>
因此,只需检查false,就可以确定数组是否是关联的。
答案 57 :(得分:-5)
如果您只寻找非数字键(无论订单如何),那么您可能需要尝试
function IsAssociative($array)
{
return preg_match('/[a-z]/i', implode(array_keys($array)));
}