PHP中如何合并相邻且价格相同的日期范围
合并相邻且价格相同的日期范围问题
现有日期范围数组
/* 日期格式 'yyyy-mm-dd' */ $existingRanges = [ ['start_date' => '2023-11-22', 'end_date' => '2023-11-30', 'price' => 200], ['start_date' => '2023-12-10', 'end_date' => '2023-12-14', 'price' => 100], ['start_date' => '2023-12-15', 'end_date' => '2023-12-20', 'price' => 100], ['start_date' => '2023-12-21', 'end_date' => '2023-12-27', 'price' => 100], ['start_date' => '2024-01-05', 'end_date' => '2024-01-05', 'price' => 600], ['start_date' => '2024-01-06', 'end_date' => '2024-01-07', 'price' => 700], ['start_date' => '2024-01-08', 'end_date' => '2024-01-20', 'price' => 700], ['start_date' => '2024-01-21', 'end_date' => '2024-01-31', 'price' => 100], ];
需求说明
合并所有相邻且价格相同的日期范围:若后一个区间的起始日期是前一个区间结束日期的次日,且两者价格一致,则将两个区间合并为一个——起始日期取前者的start_date,结束日期取后者的end_date,价格保持不变。
例如:2024-01-06至2024-01-07与2024-01-08至2024-01-20价格均为700且相邻,合并后为2024-01-06至2024-01-20、价格700的范围。
期望结果数组
$results = [ ['start_date' => '2023-11-22', 'end_date' => '2023-11-30', 'price' => 200], ['start_date' => '2023-12-10', 'end_date' => '2023-12-27', 'price' => 100], ['start_date' => '2024-01-05', 'end_date' => '2024-01-05', 'price' => 600], ['start_date' => '2024-01-06', 'end_date' => '2024-01-20', 'price' => 700], ['start_date' => '2024-01-21', 'end_date' => '2024-01-31', 'price' => 100], ];
尝试的代码(未达到预期)
function mergeDateRanges($p_arrDateranges) { // sort by start date /* usort($p_arrDateranges, function($a1, $a2) { return $a1['start_date'] === $a2['start_date'] ? 0 : ($a1['start_date'] < $a2['start_date'] ? -1 : 1); }); */ $finalArray = []; $arrMerged = array(); $arrLastDR = null; foreach ($p_arrDateranges as $arrDR) { if ($arrLastDR === null) { $arrLastDR = $arrDR; continue; } if(!$arrMerged) { array_push($arrMerged, $arrLastDR); } $endDate = DateTime::createFromFormat('Y-m-d', $arrLastDR['end_date']); $sLastDateE_1 = $endDate->modify('+1 day')->format('Y-m-d'); if (strtotime($arrDR['start_date']) < strtotime($sLastDateE_1) && $arrDR['price'] == $arrLastDR['price']) { array_push($finalArray, [ 'start_date' => $arrDR['start_date'], 'end_date' => $arrLastDR['end_date'], 'price' => 0 ]); } else { array_push($finalArray, $arrDR); } $arrLastDR = $arrDR; array_push($arrMerged, $arrLastDR); //print_r($arrLastDR); } return $finalArray; } mergeDateRanges($existingRanges);
问题分析与修正方案
原代码问题
- 数组逻辑混乱:同时维护
$finalArray和$arrMerged两个数组,职责不明确,导致输出结果错误 - 合并条件处理错误:相邻判断逻辑有误,合并时生成反向日期、0价格的无效条目
- 未正确维护合并区间:没有更新已合并区间的结束日期,而是直接添加新条目
修正后的代码
function mergeDateRanges($p_arrDateranges) { // 按start_date排序,确保输入无序时也能正确合并 usort($p_arrDateranges, function($a, $b) { return strtotime($a['start_date']) - strtotime($b['start_date']); }); if (empty($p_arrDateranges)) { return []; } $merged = [$p_arrDateranges[0]]; foreach (array_slice($p_arrDateranges, 1) as $range) { // 获取结果数组中最后一个已合并的区间 $last = &$merged[count($merged) - 1]; // 计算上一个区间结束日期的次日 $nextDay = (new DateTime($last['end_date']))->modify('+1 day')->format('Y-m-d'); // 判断是否满足合并条件:价格相同,且当前区间的start_date等于上一个区间的次日 if ($range['price'] === $last['price'] && $range['start_date'] === $nextDay) { // 更新最后一个区间的结束日期为当前区间的结束日期 $last['end_date'] = $range['end_date']; } else { // 不满足条件,直接添加当前区间到结果数组 $merged[] = $range; } } return $merged; } // 测试调用 $results = mergeDateRanges($existingRanges); print_r($results);
代码说明
- 排序:先对输入数组按
start_date排序,确保区间按时间顺序处理 - 初始化结果数组:将第一个区间作为初始合并区间
- 遍历处理:逐个检查后续区间,与结果数组的最后一个区间对比:
- 若价格相同且当前区间起始日期是上一个区间结束的次日,则更新最后一个区间的结束日期
- 否则将当前区间加入结果数组
- 返回结果:最终得到合并后的日期范围数组
内容的提问来源于stack exchange,提问作者Hola
相关产品推荐
相关产品推荐

