PHP实现按id和name匹配合并对象数组 保留首数组值并遵循第二数组顺序
PHP按规则合并两个对象数组实现方案
问题场景
PHP开发场景下有两个待合并的对象数组,结构示例如下:
第一个数组(字段优先级更高):
[ { id: jhz, name: 'John', eyes: 'Green', description: 'Cool guy', }, { id: mbe, name: 'Mary', brand: 'M&B', text: 'Something', } ]
第二个数组(决定最终排序):
[ { id: jhz, name: 'John', eyes: '', }, { id: mbe, name: 'Mary', }, { id: 'beh', name: 'Bernard', } ]
合并规则
- 匹配逻辑:以
id和name两个字段作为唯一匹配依据 - 固定字段要求:
id和name两个键全程保留原有值,不允许被其他值覆盖 - 字段优先级:除上述两个固定字段外,其余键值对统一合并,键名重复时优先使用第一个数组中的对应值覆盖
- 排序要求:最终合并结果的元素顺序,必须与第二个数组的元素顺序完全一致
上述示例对应的期望输出结果:
[ { id: jhz, name: 'John', eyes: 'Green', description: 'Cool guy', }, { id: mbe, name: 'Mary', brand: 'M&B', text: 'Something', }, { id: 'beh', name: 'Bernard', } ]
实现代码
核心思路是先对高优先级的第一个数组做索引映射,减少匹配时的循环开销,再按第二个数组的顺序遍历合并,通过数组合并顺序控制字段优先级,同时对固定字段做双重保留校验。
function mergeSpecifiedArrays(array $firstArr, array $secondArr): array { // 构建第一个数组的匹配映射,用id和name拼接作为唯一键,避免单字段重复匹配错误 $firstLookup = []; foreach ($firstArr as $item) { $item = is_object($item) ? (array)$item : $item; $matchKey = sprintf('%s|%s', $item['id'], $item['name']); $firstLookup[$matchKey] = $item; } $mergedResult = []; // 直接遍历第二个数组生成结果,天然保证顺序一致 foreach ($secondArr as $item) { $current = is_object($item) ? (array)$item : $item; $matchKey = sprintf('%s|%s', $current['id'], $current['name']); // 以当前第二个数组的元素为基础 $mergedItem = $current; if (isset($firstLookup[$matchKey])) { // 过滤掉第一个数组中的id和name字段,避免覆盖固定值 $firstItem = array_diff_key($firstLookup[$matchKey], array_flip(['id', 'name'])); // 合并时第一个数组的字段在后,自动覆盖同键的低优先级值 $mergedItem = array_merge($mergedItem, $firstItem); } // 二次强制固定id和name的值,彻底避免异常覆盖 $mergedItem['id'] = $current['id']; $mergedItem['name'] = $current['name']; // 如需返回stdClass对象格式,取消下一行注释即可 // $mergedItem = (object)$mergedItem; $mergedResult[] = $mergedItem; } return $mergedResult; }
调用示例
$res = mergeSpecifiedArrays($firstArray, $secondArray);
说明
- 兼容输入元素为关联数组、
stdClass对象两种常用格式,可通过注释开关控制返回格式 - 时间复杂度为
O(n+m),性能优于嵌套循环匹配,适合大数组场景 - 对固定字段做了两层防护,不会出现
id/name被意外覆盖的问题 - 完全遵循字段优先级、排序要求,和示例期望输出完全一致
内容的提问来源于stack exchange,提问作者OurBG
相关产品推荐
相关产品推荐

