
本文介绍如何将具有重复 id 的扁平关联数组,高效重组为以 id 为键、合并同名人员及其多爱好列表的嵌套结构,避免常见逻辑错误(如误用 in_array、未初始化数组等)。
本文介绍如何将具有重复 id 的扁平关联数组,高效重组为以 id 为键、合并同名人员及其多爱好列表的嵌套结构,避免常见逻辑错误(如误用 in_array、未初始化数组等)。
在实际开发中(尤其是处理数据库一对多关系时),我们常遇到类似这样的原始数据:多个记录共享同一用户 ID,但携带不同的子项(如爱好、订单、标签等)。目标是将其聚合成每个用户仅出现一次、且其子项归入统一数组的结构——这正是典型的“按 ID 分组 + 嵌套聚合”需求。
上述问题中的原始数组 persons 包含重复 id(如 id => 1 出现两次),而期望输出 new_persons 是一个去重后的数组,每个元素包含 id、name 和 hobbies 子数组。关键在于:不能简单遍历追加,而需以 id 为索引动态构建与累加。
以下是正确、简洁且健壮的实现方式:
$new_persons = [];
foreach ($persons as $item) {
$id = $item['id'];
// 若该 id 尚未初始化,则创建基础结构(只执行一次)
if (!isset($new_persons[$id])) {
$new_persons[$id] = [
'id' => $id,
'name' => $item['name'],
'hobbies' => []
];
}
// 无论是否首次出现,均向 hobbies 数组追加当前爱好
$new_persons[$id]['hobbies'][] = [
'hobbyId' => $item['hobbyId'],
'hobbyName' => $item['hobbyName']
];
}
// 最终转为数值索引数组(如需保持原始顺序且不依赖 key)
$new_persons = array_values($new_persons);
✅ 关键修正点说明:
- ❌ 错误写法中使用 in_array($item['id'], $newArray) 判断存在性——这是对值的线性搜索,无法准确判断 id 是否已作为键存在,且性能差(O(n));
- ✅ 正确做法是用 isset($new_persons[$id]) 检查键是否存在(O(1)),语义清晰、效率高;
- ❌ 原代码中 $newArray 未正确定义,且混用 array_push 与 [] 语法,导致结构混乱;
- ✅ 新方案统一使用 [] 追加,确保 hobbies 始终为数组,并在首次访问时初始化为空数组。
? 额外建议:
- 若原始数据中 name 可能因数据不一致而不同(如同一 id 对应不同 name),应在首次初始化时校验或抛出警告;
- 如需严格保持原始记录顺序(如按首次出现的 id 排序),可额外维护一个 ids_seen = [] 数组记录顺序,最后按此顺序 array_map 提取;
- 在 Laravel 或现代 PHP 环境中,也可借助 collect($persons)->groupBy('id')->map() 链式调用简化逻辑,但底层原理一致。
最终输出将严格符合预期结构,且具备良好的可读性、可维护性与扩展性。











