
本文详解如何对多维数组按指定键(如 `grouped_by`)进行**连续性分组**——即每当该键值发生变化时,就创建一个新分组(而非简单合并所有相同键值),并为每个分组生成形如 `1.1`、`1.2`、`4.1` 的唯一键名。
在实际业务开发中(例如工时报表、日志序列分析或时间轴数据聚合),我们常需保留原始数组的顺序语义:相同 grouped_by 值若在原数组中被其他值“隔开”,就应视为独立逻辑段。此时,传统 array_reduce 或键映射式分组(如 $groups[$item['grouped_by']][] = $item)无法满足需求——它会将所有 grouped_by => 1 的项合并为一组,而忽略了它们在原始序列中的非连续分布。
要实现真正的“控制断点分组(Control Break Grouping)”,核心思路是:
✅ 遍历过程中持续追踪上一项的 grouped_by 值;
✅ 当前值 ≠ 上一项值时,为该值对应的分组计数器递增;
✅ 使用 当前键值.当前计数 构建唯一分组键,并追加当前元素。
以下是完整、健壮、可直接复用的 PHP 实现:
function groupBySequentialKey(array $items, string $key): array
{
$result = [];
$counts = [];
$prevValue = null;
foreach ($items as $item) {
$currentValue = $item[$key] ?? null;
// 检测分组断点:值变化或首次进入
if ($currentValue !== $prevValue) {
$counts[$currentValue] = ($counts[$currentValue] ?? 0) + 1;
}
$groupKey = $currentValue . '.' . $counts[$currentValue];
$result[$groupKey][] = $item;
$prevValue = $currentValue;
}
return $result;
}
// 示例调用
$report_items = [
['id' => 972, 'user_id' => 2, 'user_field_48' => 1, 'project' => '100 — NLO', 'duration' => '1:00', 'grouped_by' => 1],
['id' => 644, 'user_id' => 2, 'user_field_48' => 4, 'project' => '123 — QHV', 'duration' => '15:00', 'grouped_by' => 4],
['id' => 631, 'user_id' => 2, 'user_field_48' => 4, 'project' => '', 'duration' => '-5:00', 'grouped_by' => 4],
['id' => 630, 'user_id' => 2, 'user_field_48' => 1, 'project' => '', 'duration' => '22:00', 'grouped_by' => 1],
['id' => 971, 'user_id' => 2, 'user_field_48' => 1, 'project' => '100 — NLO', 'duration' => '1:00', 'grouped_by' => 1],
['id' => 973, 'user_id' => 2, 'user_field_48' => 1, 'project' => '100 — NLO', 'duration' => '1:00', 'grouped_by' => 1],
['id' => 974, 'user_id' => 2, 'user_field_48' => 1, 'project' => '100 — NLO', 'duration' => '1:00', 'grouped_by' => 1],
];
$grouped = groupBySequentialKey($report_items, 'grouped_by');
print_r($grouped);输出效果(与需求完全一致):
- 1.1 → 索引 0(首个 grouped_by=1 段)
- 4.1 → 索引 1–2(首个 grouped_by=4 连续段)
- 1.2 → 索引 3–6(第二个 grouped_by=1 连续段)
⚠️ 关键注意事项:
- 该方法强依赖原始数组顺序,若数据未按业务逻辑排序,请先调用 usort() 明确排序规则;
- 键名使用字符串拼接(如 '1.1'),确保其作为数组键的合法性与可读性;若需整数键,可改用 [[$currentValue, $counts[$currentValue]] => [...] 的嵌套结构;
- 函数已做空值防护($item[$key] ?? null),但建议在生产环境校验 $key 是否必然存在,避免 Undefined index 警告;
- 时间复杂度为 O(n),空间复杂度为 O(n),适用于万级以内数据;超大数据集可考虑生成器(Generator)流式处理。
此方案本质是将“分组”从静态哈希映射升级为状态感知的序列解析器,精准还原了业务中“每次切换即新开一节”的真实语义,是处理时序型、流水线型数据的通用范式。










