在PHP中判断数组是否连续,通常指数组元素为连续整数(如[1,2,3]或[5,4,3]),实现方法:先通过array_unique()去重,再排序(升序/降序),然后遍历检查相邻元素差是否为1,更高效的方式是数学验证:若max($arr) - min($arr) + 1 == count(array_unique($arr)),则数组连续,需注意单元素数组默认连续,空数组可视为非连续,此方法适用于无重复元素的连续整数判断,适用于数据校验、序列验证等场景。
PHP如何高效判断数组是否连续:方法解析与代码实践
在PHP开发中,判断数组是否"连续"是一个常见需求,这里的"连续"通常指数组元素在数学上构成连续的整数序列(如[1,2,3,4]或[5,4,3,2]),或字符串数组按字母顺序连续(如['a','b','c']),本文将详细解析不同场景下的判断方法,并提供可落地的代码实现。
明确"连续"的定义
在开始编码前,需先明确"连续"的具体场景,常见的定义包括:
- 升序连续整数:元素按从小到大排列,且相邻元素差为1(如
[3,4,5,6]); - 降序连续整数:元素按从大到小排列,且相邻元素差为-1(如
[8,7,6,5]); - 允许重复的连续整数:元素可重复,但核心序列连续(如
[1,2,2,3]是否算连续需明确需求); - 字符串连续:按字母顺序连续(如
['x','y','z'],即ASCII码连续); - 环形连续:首尾相连的连续序列(如
[3,4,5,1,2])。
本文以不重复的整数数组连续判断为核心,兼顾其他场景的扩展方案。
核心方法:升序/降序连续判断
方法思路
判断数组是否连续,核心逻辑是:
- 升序连续:数组排序后,每个元素比前一个元素大1;
- 降序连续:数组排序后,每个元素比前一个元素小1;
- 边界情况:空数组或单元素数组,通常视为"连续"(可根据需求调整);
- 性能考虑:对于大数组,应避免不必要的排序操作。
代码实现
以下是一个通用的判断函数,支持升序/降序模式,并允许配置是否允许重复元素:
/**
* 判断数组是否连续(整数序列)
* @param array $arr 待判断数组
* @param string $order 排序方向:'asc'(升序)或'desc'(降序)
* @param bool $allowDuplicates 是否允许重复元素
* @return bool
*/
function isConsecutiveArray(array $arr, string $order = 'asc', bool $allowDuplicates = false): bool
{
// 边界情况:空数组或单元素数组,视为连续
if (count($arr) <= 1) {
return true;
}
// 去重(如果不允许重复)
if (!$allowDuplicates) {
$uniqueArr = array_unique($arr);
if (count($uniqueArr) !== count($arr)) {
return false; // 存在重复元素,直接返回false
}
$arr = $uniqueArr;
}
// 排序(升序或降序)
if ($order === 'asc') {
sort($arr);
} else {
rsort($arr);
}
// 遍历判断相邻元素差是否为1(升序)或-1(降序)
for ($i = 1; $i < count($arr); $i++) {
$prev = $arr[$i - 1];
$current = $arr[$i];
if ($order === 'asc' && $current - $prev !== 1) {
return false;
}
if ($order === 'desc' && $prev - $current !== 1) {
return false;
}
}
return true;
}
性能优化版本
对于大型数组,我们可以优化性能,避免不必要的排序操作:
/**
* 高效判断数组是否连续(无需排序)
* @param array $arr 待判断数组
* @return bool
*/
function isConsecutiveArrayOptimized(array $arr): bool
{
if (count($arr) <= 1) {
return true;
}
$min = min($arr);
$max = max($arr);
// 检查元素数量是否等于范围大小
if (count($arr) !== $max - $min + 1) {
return false;
}
// 检查是否所有元素都存在
$expectedRange = range($min, $max);
return count(array_diff($arr, $expectedRange)) === 0;
}
测试用例
// 测试升序连续 var_dump(isConsecutiveArray([1, 2, 3, 4])); // bool(true) var_dump(isConsecutiveArray([1, 3, 4, 5])); // bool(false) // 测试降序连续 var_dump(isConsecutiveArray([5, 4, 3, 2], 'desc')); // bool(true) var_dump(isConsecutiveArray([5, 3, 2, 1], 'desc')); // bool(false) // 测试允许重复 var_dump(isConsecutiveArray([1, 2, 2, 3], 'asc', true)); // bool(true) var_dump(isConsecutiveArray([1, 2, 2, 3], 'asc', false)); // bool(false) // 边界情况 var_dump(isConsecutiveArray([])); // bool(true) var_dump(isConsecutiveArray([42])); // bool(true) // 性能优化版本测试 var_dump(isConsecutiveArrayOptimized([10, 11, 12, 13])); // bool(true) var_dump(isConsecutiveArrayOptimized([10, 12, 13, 14])); // bool(false)
扩展应用场景
字符串数组连续判断
/**
* 判断字符串数组是否按字母顺序连续
* @param array $arr 待判断数组
* @return bool
*/
function isStringArrayConsecutive(array $arr): bool
{
if (count($arr) <= 1) {
return true;
}
sort($arr);
for ($i = 1; $i < count($arr); $i++) {
if (ord($arr[$i]) - ord($arr[$i - 1]) !== 1) {
return false;
}
}
return true;
}
// 测试
var_dump(isStringArrayConsecutive(['a', 'b', 'c'])); // bool(true)
var_dump(isStringArrayConsecutive(['a', 'c', 'd'])); // bool(false)
环形连续判断
/**
* 判断数组是否环形连续(如[3,4,5,1,2])
* @param array $arr 待判断数组
* @return bool
*/
function isCircularConsecutive(array $arr): bool
{
if (count($arr) <= 1) {
return true;
}
$min = min($arr);
$max = max($arr);
// 检查是否是连续的整数范围
if (count($arr) !== $max - $min + 1) {
return false;
}
// 检查所有元素是否都存在
$expectedRange = range($min, $max);
if (count(array_diff($arr, $expectedRange)) > 0) {
return false;
}
// 检查是否可以形成环形连续
$sorted = $arr;
sort($sorted);
// 检查普通连续情况
for ($i = 1; $i < count($sorted); $i++) {
if ($sorted[$i] - $sorted[$i - 1] !== 1) {
// 如果不是普通连续,检查是否是环形连续
// 即第一个元素是max,最后一个元素是min
return $sorted[0] === $min && $sorted[count($sorted) - 1] === $max;
}
}
return true;
}
// 测试
var_dump(isCircularConsecutive([3, 4, 5, 1,