
本文详解如何将形如“dd.mm.yyyy|xx,xxx”的日期-数值对字符串解析、按月归组,并高效计算各月数值的算术平均值,全程使用 php 原生函数链式处理,兼顾可读性与实用性。
本文详解如何将形如“dd.mm.yyyy|xx,xxx”的日期-数值对字符串解析、按月归组,并高效计算各月数值的算术平均值,全程使用 php 原生函数链式处理,兼顾可读性与实用性。
在实际数据处理中,常遇到以空格分隔、含日期与带千位分隔符数值的扁平化字符串(如日度行情或日志指标)。本教程以典型场景为例:输入字符串包含多条 DD.MM.YYYY|XX,XXX 格式记录,目标是按年月(MM.YYYY)聚合所有数值,并精确计算每月算术平均值。
核心思路分为三步:拆分 → 归组 → 聚合。以下为完整、健壮且可直接运行的 PHP 实现:
<?php $input = '04.01.2021|26,140 05.01.2021|26,225 06.01.2021|26,145 07.01.2021|26,145 08.01.2021|26,165 11.02.2021|26,240 12.02.2021|26,190';
// 步骤1:将字符串按空格切分为记录,再对每条记录用 '|' 拆分为 [date, value] 数组
$records = array_map(
fn($item) => explode('|', trim($item)),
explode(' ', $input)
);
// 步骤2:按 "MM.YYYY" 归组数值(提取日期第3–9位,即 "01.2021";移除数值中的逗号并转为数字)
$groupedByMonth = array_reduce(
$records,
function ($carry, $record) {
if (count($record) !== 2) return $carry; // 安全校验:跳过格式异常项
[$date, $valueStr] = $record;
$monthKey = substr($date, 3, 7); // 提取 "MM.YYYY"(从索引3开始共7字符:"01.2021")
$cleanValue = (float) str_replace(',', '', $valueStr);
$carry[$monthKey][] = $cleanValue;
return $carry;
},
[]
);
// 步骤3:对每个月份的数值数组计算算术平均值(自动处理空数组)
$averagesPerMonth = array_map(
fn($values) => count($values) > 0 ? round(array_sum($values) / count($values), 3) : 0.0,
$groupedByMonth
);
print_r($averagesPerMonth);
// 输出示例:
// Array
// (
// [01.2021] => 26164
// [02.2021] => 26215
// )
✅ 关键说明与最佳实践:
- 日期提取鲁棒性:使用 substr($date, 3, 7) 精准截取 MM.YYYY(固定长度格式),比正则更轻量;若需支持 YYYY-MM-DD 等变体,建议改用 DateTime::createFromFormat() 解析后格式化。
- 数值清洗安全:str_replace(',', '', $valueStr) 清除千位分隔符,(float) 强制类型转换确保参与计算;对含小数点的数值(如 26,140.5)需额外处理(例如先替换 , 为 . 再转换)。
- 错误防御:代码中已加入 count($record) !== 2 校验,避免因空格冗余或格式错误导致崩溃;生产环境建议补充 is_numeric($cleanValue) 验证。
- 精度控制:round(..., 3) 保留三位小数,可根据业务需求调整(如金融场景常用 bcdiv() 保证高精度)。
该方案无需循环嵌套,全部基于函数式编程范式(array_map/array_reduce),逻辑清晰、扩展性强——如需改为按季度统计,仅需修改 $monthKey 的生成逻辑即可。










