
本文介绍在 Laravel 或原生 PHP 中,将含重复设备标识的消费记录数组转换为每组包含 start/end 时间字段的新结构,通过键映射与状态管理实现字段重命名与逻辑配对。
本文介绍在 laravel 或原生 php 中,将含重复设备标识的消费记录数组转换为每组包含 `start`/`end` 时间字段的新结构,通过键映射与状态管理实现字段重命名与逻辑配对。
在实际开发中(尤其在处理 IoT 设备上报、日志聚合或时间区间统计场景),我们常遇到类似需求:原始数据以扁平数组形式存在,每个元素包含 device、timestamp 和 value,但业务要求按设备(或设备+值)分组,并将相邻或成对的时间戳分别映射为 start 和 end 字段。注意:原始数据未排序且不保证严格两两成对,因此需明确分组逻辑与配对策略。
以下提供两种主流实现方式,均基于 PHP 原生语法,完全兼容 Laravel 环境:
✅ 方案一:简单配对(默认按设备首次出现为 start,后续同设备为 end)
适用于每设备恰好两条记录、且顺序隐含先后关系的场景(如“开始采集”和“结束采集”):
$consumos = [
["device" => "EA1", "timestamp" => "2020-01-01 21:00:00", "value" => 4],
["device" => "EA1", "timestamp" => "2020-01-01 07:00:00", "value" => 4],
["device" => "EA2", "timestamp" => "2022-01-01 12:00:00", "value" => 2],
["device" => "EA2", "timestamp" => "2022-01-01 13:00:00", "value" => 2],
];
$map = [];
foreach ($consumos as $item) {
$key = $item['device']; // 分组键:仅设备名
if (isset($map[$key])) {
// 同设备第二次出现 → 设为 end,并立即加入结果
$map[$key]['end'] = $item['timestamp'];
$result[] = $map[$key];
unset($map[$key]);
} else {
// 首次出现 → 初始化为 start
$map[$key] = [
'device' => $item['device'],
'start' => $item['timestamp'],
'value' => $item['value']
];
}
}
// 若存在未配对的单条记录(如奇数条),它们会留在 $map 中;按需处理:
foreach ($map as $orphan) {
// 可选:设 end = start,或跳过,或抛出警告
$orphan['end'] = $orphan['start'];
$result[] = $orphan;
}
print_r($result);⚠️ 注意事项与增强建议
-
时间顺序问题:示例中
"2020-01-01 07:00:00"在"2020-01-01 21:00:00"之后出现,但被当作end。若业务要求start ≤ end,请先对$consumos按timestamp排序:usort($consumos, fn($a, $b) => strtotime($a['timestamp']) <=> strtotime($b['timestamp']));
-
多维分组:若需同时按
device和value分组(避免不同 value 混淆),修改键为:$key = $item['device'] . '|' . $item['value']; // 或使用 [$item['device'], $item['value']] 作数组键
-
Laravel 风格优化:可封装为集合方法链式调用:
collect($consumos) ->groupBy('device') ->map(function ($group) { $sorted = $group->sortBy('timestamp'); return [ 'device' => $group->first()['device'], 'start' => $sorted->first()['timestamp'], 'end' => $sorted->last()['timestamp'], 'value' => $group->first()['value'], ]; }) ->values() ->toArray();
最终输出符合预期:
立即学习“PHP免费学习笔记(深入)”;
[ ["device"=>"EA1", "start"=>"2020-01-01 21:00:00", "end"=>"2020-01-01 07:00:00", "value"=>4], ["device"=>"EA2", "start"=>"2022-01-01 12:00:00", "end"=>"2022-01-01 13:00:00", "value"=>2] ]
核心要点:字段重命名本质是键映射,而结构重组依赖分组策略与状态跟踪。根据实际数据特征选择方案,并务必验证时间逻辑与边界情况。



















