
本文详解如何在 php 中对具有相同 id 的多维数组元素进行深度合并,避免简单去重导致的数据丢失,重点解决 providerdetails 等嵌套结构的合理聚合问题。
本文详解如何在 php 中对具有相同 id 的多维数组元素进行深度合并,避免简单去重导致的数据丢失,重点解决 providerdetails 等嵌套结构的合理聚合问题。
在实际开发中,常遇到从多个数据源(如 API 聚合、数据库查询)获取的二维/多维数组存在重复主键(如 "id": "22"),但各条目携带互补的业务字段(如不同 provider_id 对应的 providerDetails)。此时,若直接使用 array_unique($arr, SORT_REGULAR),虽能去除完全相同的项,却无法合并逻辑上属于同一实体(同 id)但内容互补的记录——这正是本教程要解决的核心问题。
❌ 错误认知:array_unique() 不能直接用于“智能合并”
原答案中建议的 array_unique($array, SORT_REGULAR) 仅适用于完全一致的数组项去重。而题中示例中两个 "id": "22" 的条目在 provider_id、providerDetails 等关键字段上明显不同,SORT_REGULAR 比较会将它们视为不重复项,因此该方案无法达成题目要求的“合并到 id '22'”目标。
✅ 正确思路:按 ID 分组 + 深度合并(Deep Merge)
我们需要:
- 按 id 字段分组,将所有同 ID 元素归入一个桶;
- 对每个桶内元素执行深度合并:基础字段(如 name, is_current)可保留首个值;嵌套数组(如 providerDetails.providerService, providerDetails.provider_rating)需去重合并;冲突字段(如 providerDetails.email)可根据业务规则选择覆盖或合并。
以下为推荐实现方案:
<?php function mergeArraysById(array $items): array {
$grouped = [];
// 步骤1:按 id 分组
foreach ($items as $item) {
$id = $item['id'] ?? '';
if (!isset($grouped[$id])) {
$grouped[$id] = $item;
// 初始化 providerDetails 为数组容器(确保后续可安全合并)
if (isset($item['providerDetails'])) {
$grouped[$id]['providerDetails'] = $item['providerDetails'];
} else {
$grouped[$id]['providerDetails'] = [];
}
} else {
// 步骤2:深度合并 providerDetails 及其他字段
if (isset($item['providerDetails']) && is_array($item['providerDetails'])) {
$grouped[$id]['providerDetails'] = deepMerge(
$grouped[$id]['providerDetails'],
$item['providerDetails']
);
}
// 其他顶层字段:默认保留第一个出现的值(如 name, is_current)
// 如需覆盖策略,可在此处添加逻辑
}
}
return array_values($grouped);
}
// 通用深度合并函数(支持递归数组合并 + 数值索引去重)
function deepMerge(array $a, array $b): array {
$result = $a;
foreach ($b as $key => $value) {
if (is_array($value) && isset($a[$key]) && is_array($a[$key])) {
// 关联数组:递归合并
$result[$key] = deepMerge($a[$key], $value);
} elseif (is_numeric($key) && is_array($value)) {
// 数值索引数组:去重后合并(如 providerService, locationService)
$result[$key] = array_values(array_unique(
array_merge($a[$key] ?? [], $value),
SORT_REGULAR
));
} else {
// 标量或新键:直接赋值(后出现的覆盖前一个)
$result[$key] = $value;
}
}
return $result;
}
// 使用示例
$json = '[{
"id": "22",
"name": "Respite",
"provider_id": "7",
"is_current": 0,
"providerDetails": {
"id": "7",
"name": "Pankaj ji Service Provider4",
"email": "pankaj@example.com",
"providerService": ["22"],
"provider_rating": []
}
}, {
"id": "22",
"name": "Respite",
"provider_id": "1",
"is_current": 0,
"providerDetails": {
"id": "1",
"name": "Service 1",
"email": "service1@example.com",
"providerService": ["4","7","22","23","27"],
"provider_rating": [{"rating":"4"},{"rating":"5"}]
}
}]';
$original = json_decode($json, true);
$merged = mergeArraysById($original);
echo json_encode($merged, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
?>
⚠️ 关键注意事项
- 字段优先级需明确:providerDetails.email 在两条记录中不同,上述代码采用“后者覆盖前者”。若需保留非空值或做业务判断(如优先取 verified 邮箱),请在 deepMerge 中定制逻辑。
- 数值索引数组自动去重:providerService、locationService 等列表类字段已通过 array_unique(..., SORT_REGULAR) 去重并重排索引,避免重复 ID。
- provider_rating 合并策略:示例中将其视为对象数组,直接追加。若需去重(如按 provider_feedback_id 去重),需额外实现基于键的合并逻辑。
- 性能提示:对于超大数据集(>10,000 条),建议改用生成器或数据库层聚合(如 GROUP BY id + JSON_AGG)。
✅ 总结
处理多维数组中“同 ID 多记录”的合并,本质是分组 + 智能聚合,而非简单去重。array_unique() 仅适用于完全重复项剔除,而真实场景需要的是语义级合并。掌握 deepMerge 模式并根据业务定义字段合并策略(覆盖、追加、取优),才能稳健应对 providerDetails 等复杂嵌套结构的整合需求。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











