PHP将所有数组都视为关联数组,因此没有任何内置函数。谁能推荐一种相当有效的方法来检查数组是否“是一个列表”(只包含从0开始的数字键)?
基本上,我希望能够区分这些:
$sequentialArray = [
'apple', 'orange', 'tomato', 'carrot'
];
这:
$assocArray = [
'fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot'
];
我认为下面两个函数是最好的方法去检查'如果一个数组是结合或数字'。由于'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));
}
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:
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.
请记住,数组键只能是整数或字符串,严格的数字字符串,如“1”(但不是“01”)将被转换为整数。如果您希望数组是顺序的,这使得检查整数键成为除了计数之外唯一需要的操作。当然,如果is_indexed_array返回false,则可以将该数组视为关联数组。我说“见过”,因为事实上它们都是。
我想出了下一个方法:
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”;显示内存使用情况
我认为标量数组的定义因应用程序而异。也就是说,一些应用程序将需要更严格的定义标量数组,而一些应用程序将需要更宽松的定义。
下面我将介绍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;
}
/*
iszba - Is Zero Based Array
Detects if an array is zero based or not.
PARAMS:
$chkvfnc
Callback in the loop allows to check the values of each element.
Signature:
bool function chkvfnc($v);
return:
true continue looping
false stop looping; iszba returns false too.
NOTES:
○ assert: $array is an array.
○ May be memory efficient;
it doesn't get extra arrays via array_keys() or ranges() into the function.
○ Is pretty fast without a callback.
○ With callback it's ~2.4 times slower.
*/
function iszba($array, $chkvfnc=null){
$ncb = !$chkvfnc;
$i = 0;
foreach($array as $k => $v){
if($k === $i++)
if($ncb || $chkvfnc($v))
continue;
return false;
}
return true;
}
•没有回调,比当前领先的回答快30%。
而且可能内存效率更高。
•只需对答案求反,就可以知道数组是否应该被认为是关联的。