PHP将所有数组都视为关联数组,因此没有任何内置函数。谁能推荐一种相当有效的方法来检查数组是否“是一个列表”(只包含从0开始的数字键)?
基本上,我希望能够区分这些:
$sequentialArray = [
'apple', 'orange', 'tomato', 'carrot'
];
这:
$assocArray = [
'fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot'
];
我想出了下一个方法:
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 -不管它是正负,它是空的。
与上面列出的一些方法相比,这种方法的优点如下:
它不涉及数组的复制(有人在这个要点https://gist.github.com/Thinkscape/1965669中提到array_values不涉及复制-什么!??它确实如此-如下所示)
对于更大的数组,它更快,同时对内存更友好
我使用了Artur Bodera提供的基准测试,其中我将其中一个数组更改为1M个元素(array_fill(0, 1000000, uniqid()), //大数字数组)。
以下是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”;显示内存使用情况
这是函数-
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相关函数的另一种方式。我还没有检查这个解决方案在性能方面如何与其他已经在这里发布的解决方案相比。但它确实帮助我解决了这个问题。希望这能有所帮助。
检查数组是否有所有的关联键。使用stdClass & 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只返回可访问的属性(请参阅在将数组转换为对象期间发生的更多信息)。然后,只是逻辑上:如果基本数组元素的计数等于对象的可访问属性的计数-所有键都是关联的。
一些测试:
$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
Etc.
我认为标量数组的定义因应用程序而异。也就是说,一些应用程序将需要更严格的定义标量数组,而一些应用程序将需要更宽松的定义。
下面我将介绍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;
}
我的解决方案:
function isAssociative(array $array)
{
return array_keys(array_merge($array)) !== range(0, count($array) - 1);
}
单个数组上的Array_merge将重新索引所有整数键,但不包括其他键。例如:
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开始重新索引列表。