如何遵循函数式编程原则改写PHP日期区间索引查找函数?
用函数式编程实现日期区间索引匹配
问题背景
有一个存储「日期上限」的数组 [30,60,90,120,360],对应天数区间如下:
Index : Interval
0 : 0-30
1 : 31-60
2 : 61-90
3 : 91–360
4 : 361 – infinity
给定任意天数x,需要用函数式编程确定它所属区间的索引(例如75天对应索引2)。以下是用户已实现的循环版本代码:
function indexByDateRange(array $intervalRange, int $days) { foreach ($intervalRange as $i=>$value) { if ($days <= $value) { return $i; } } return count($intervalRange); } $index = indexByDateRange(array(30,60,90,120,360), 73); // 73属于61-90区间,返回2 $index = indexByDateRange(array(30,60,90,120,360), 4); // 4属于0-30区间,返回0
函数式改写方案
1. 递归实现(纯函数式)
递归是函数式编程中替代循环的常用方式,以下实现完全符合纯函数要求:
- 无副作用,输入相同参数返回固定结果
- 依赖递归遍历数组,无显式循环
- 基线条件明确(数组为空时返回当前索引)
function indexByDateRangeRecursive(array $intervalRange, int $days, int $currentIndex = 0): int { // 基线条件:数组为空,返回当前索引(即原数组长度) if (empty($intervalRange)) { return $currentIndex; } // 取数组第一个元素判断 $firstLimit = reset($intervalRange); if ($days <= $firstLimit) { return $currentIndex; } // 递归处理剩余数组,索引自增 return indexByDateRangeRecursive(array_slice($intervalRange, 1), $days, $currentIndex + 1); } // 测试示例 echo indexByDateRangeRecursive([30,60,90,120,360], 73); // 输出:2 echo indexByDateRangeRecursive([30,60,90,120,360], 4); // 输出:0 echo indexByDateRangeRecursive([30,60,90,120,360], 400); // 输出:5
2. 利用高阶函数实现
PHP内置的array_reduce是典型的高阶函数,可用于实现函数式的遍历逻辑,无需显式递归或循环:
function indexByDateRangeFunctional(array $intervalRange, int $days): int { $matchedIndex = array_reduce( $intervalRange, function ($carry, $limit) use ($days, $intervalRange) { // 未找到匹配项时,检查当前上限是否符合条件 if ($carry === null && $days <= $limit) { return array_search($limit, $intervalRange); } return $carry; }, null ); // 未匹配到任何上限时,返回数组长度 return $matchedIndex ?? count($intervalRange); } // 测试示例 echo indexByDateRangeFunctional([30,60,90,120,360], 73); // 输出:2 echo indexByDateRangeFunctional([30,60,90,120,360], 4); // 输出:0 echo indexByDateRangeFunctional([30,60,90,120,360], 400); // 输出:5
函数式特性说明
以上两种实现都遵循函数式编程核心原则:
- 纯函数:仅依赖输入参数,无外部状态修改,相同输入始终返回相同结果
- 无副作用:不会改变输入数组或外部变量
- 避免可变状态:递归版本通过参数传递索引,高阶函数版本通过闭包传递状态,均无可变变量
内容的提问来源于stack exchange,提问作者Armin66
相关产品推荐
相关产品推荐

