如何检查PHP数组是关联的还是顺序的?
PHP将所有数组视为关联数组,因此没有任何内置函数。有人能推荐一种相当有效的方法来检查数组是否只包含数字键吗 基本上,我希望能够区分这两种情况:如何检查PHP数组是关联的还是顺序的?,php,arrays,Php,Arrays,PHP将所有数组视为关联数组,因此没有任何内置函数。有人能推荐一种相当有效的方法来检查数组是否只包含数字键吗 基本上,我希望能够区分这两种情况: $sequentialArray = [ 'apple', 'orange', 'tomato', 'carrot' ]; 这是: $assocArray = [ 'fruit1' => 'apple', 'fruit2' => 'orange', 'veg1' => 'tomato', 'v
$sequentialArray = [
'apple', 'orange', 'tomato', 'carrot'
];
这是:
$assocArray = [
'fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot'
];
您提出了两个不完全相同的问题:
- 首先,如何确定数组是否只有数字键
- 其次,如何确定数组是否具有从0开始的顺序数字键
函数isAssoc(数组$arr)
{
if(array()==$arr)返回false;
返回数组_键($arr)!==范围(0,计数($arr)-1);
}
变量转储(isAssoc(['a','b','c']);//假的
变量转储(isAssoc([“0”=>“a”、“1”=>“b”、“2”=>“c”]);//假的
变量转储(isAssoc([“1”=>“a”、“0”=>“b”、“2”=>“c”]);//真的
变量转储(isAssoc([“a”=>“a”、“b”=>“b”、“c”=>“c”]);//真的
这肯定是一个更好的选择
<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;
实际上,最有效的方法是:
function is_assoc($array){
$keys = array_keys($array);
return $keys !== array_keys($keys);
}
这是因为它比较了键(对于顺序数组,总是0,1,2等)和键的键(总是0,1,2等)。我使用了两个
数组_键($obj)!=范围(0,计数($obj)-1)
和数组_值($arr)!=$arr
(虽然第二个比第一个便宜,但它们彼此都是对偶的),但对于非常大的阵列,两者都失败
这是因为array\u键
和array\u值
都是非常昂贵的操作(因为它们构建了一个大小与原始数组大致相同的全新数组)
与上述方法相比,以下函数更稳健:
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;
}
函数数组类型($obj){
$last_key=-1;
$type='index';
foreach($obj as$key=>$val){
如果(!is_int($key)|$key<0){
返回“assoc”;
}
如果($key!==$last_key+1){
$type='sparse';
}
$last_key=$key;
}
返回$type;
}
还请注意,如果不想区分稀疏数组和关联数组,只需从两个if
块返回'assoc'
最后,虽然这看起来不像本页上的许多“解决方案”那么“优雅”,但实际上它的效率要高得多。几乎任何关联数组都会立即被检测到。只有索引数组才会被彻底检查,上述方法不仅会彻底检查索引数组,还会复制它们。此函数可以处理:
- 索引中有孔的阵列(例如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;
}
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;
}
要仅检查数组是否具有非整数键(而不是数组是顺序索引还是零索引):
如果至少有一个字符串键,
$array
将被视为关联数组。这是解决方案吗
public static function isArrayAssociative(array $array) {
reset($array);
return !is_int(key($array));
}
很明显,需要注意的是数组光标被重置了,但我想说的是,可能在遍历或使用数组之前就已经使用了该函数。这个问题中的许多评论者不理解数组在PHP中是如何工作的。从: 键可以是整数或字符串。如果一个键是一个整数的标准表示形式,它将被解释为这样(即,“8”将被解释为8,而“08”将被解释为“08”)。键中的浮点被截断为整数。索引数组类型和关联数组类型在PHP中是相同的类型,可以包含整数和字符串索引 换句话说,数组键“8”是不存在的,因为它总是(静默地)转换为整数8。因此,尝试区分整数和数字字符串是不必要的 如果您希望以最有效的方式检查数组中的非整数键,而无需复制数组的一部分(如array_keys()所做的)或全部(如foreach所做的),请执行以下操作:
这是因为key()在当前数组位置无效时返回NULL,并且NULL永远不能是有效的键(如果尝试将NULL用作数组键,它会被静默转换为“”。我使用的方法如下:
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
速度方面:
function isAssoc($array)
{
return ($array !== array_values($array));
}
function isAssoc($array)
{
$array = array_keys($array); return ($array !== array_keys($array));
}
内存方面:
function isAssoc($array)
{
return ($array !== array_values($array));
}
function isAssoc($array)
{
$array = array_keys($array); return ($array !== array_keys($array));
}
这两个得分最高的示例都不能正确地使用数组,例如$array=array('foo'=>'bar',1)
这也适用():
请注意,此答案的要点是通知您是否存在
SplFixedArray
,而不是鼓励您在此类测试中使用异常。我认为以下两个函数是检查“数组是关联的还是数字的”的最佳方法。由于“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,因此,如果不需要指定另一个基值,则可以忽略该值。如果读取的po
function array_has_numeric_keys_only(array $array)
{
try {
SplFixedArray::fromArray($array, true);
} catch (InvalidArgumentException $e) {
return false;
}
return true;
}
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));
}
//! 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);
}
//! 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);
}
//! 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;
}
//! 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);
}
array(0 => "b");
array(13 => "b");
array(-13 => "b"); // Negative integers are also integers.
array(0x1A => "b"); // Hexadecimal notation.
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");
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.
array("60000000000" => "b"); // Array key could be integer or string, it can fit into a 64-bit (but not 32-bit) integer.
array(1) {
[2147483647]=>
string(1) "b"
}
array(1) {
["2147483647"]=>
string(1) "b"
}
<?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;
}
$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";
function isNumericArray($array) {
$count = count($array);
for ($i = 0; $i < $count; $i++) {
if (!isset($array[$i])) {
return FALSE;
}
}
return TRUE;
}
function isAssociative(array $array)
{
return array_keys(array_merge($array)) !== range(0, count($array) - 1);
}
array_merge([1 => 'One', 3 => 'Three', 'two' => 'Two', 6 => 'Six']);
// This will returns [0 => 'One', 1 => 'Three', 'two' => 'Two', 2 => 'Six']
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__)
);
}
}
if (array_is_indexed($array)) { }
if (array_is_assoc($array)) { }
// Too short :)
function is_assoc($arr) {
ksort($arr);
return json_encode($arr)[0] === '{';
}
function array_is_assoc(array $a) {
$i = 0;
foreach ($a as $k => $v) {
if ($k !== $i++) {
return true;
}
}
return false;
}
<?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
/**
* 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;
}
Arr::isAssoc($array)
Arr:isAssoc($array, true)
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;
}