
本教程将指导您如何在PHP中高效地合并两个数组。我们将探讨一种场景,其中一个数组包含基于共同标识符(如epid)的重复记录,而另一个数组是目标结构。目标是将第一个数组中所有匹配标识符的特定字段(如hash)聚合到一个子数组中,并添加到第二个数组的相应记录中,从而实现数据的深度整合。
引言:PHP数组数据整合的挑战
在php开发中,我们经常需要处理来自不同源或具有不同结构的数据集,并将其整合以满足特定的业务需求。一个常见的挑战是,当一个数组包含基于某个共同标识符的重复记录,而另一个数组是我们的目标结构时,如何将第一个数组中所有匹配标识符的特定属性聚合起来,并添加到目标数组的相应记录中。
例如,假设我们有两个数组:
数组1 (源数据): 包含产品ID (epid) 和哈希值 (hash)。同一个epid可能出现多次,每个都有一个hash值。
[ ["epid" => "123", "hash" => "xxxxxxA"], ["epid" => "456", "hash" => "xxxxxxB"], ["epid" => "789", "hash" => "xxxxxxC"], ["epid" => "123", "hash" => "xxxxxxD"], ["epid" => "123", "hash" => "xxxxxxE"], ]
数组2 (目标数据): 包含产品ID (epid) 和名称 (name)。每个epid在这里是唯一的。
[ ["epid" => "123", "name" => "This is a title"], ["epid" => "456", "name" => "This is a title"], ["epid" => "789", "name" => "This is a title"] ]
我们的目标是将数组1中所有与数组2中epid匹配的hash值收集起来,形成一个hash数组,并添加到数组2的相应记录中。最终结果应如下所示:
立即学习“PHP免费学习笔记(深入)”;
[ ["epid" => "123", "name" => "This is a title", "hash" => [ "xxxxxxA", "xxxxxxD", "xxxxxxE" ] ], ["epid" => "456", "name" => "This is a title", "hash" => [ "xxxxxxB" ] ], ["epid" => "789", "name" => "This is a title", "hash" => [ "xxxxxxC" ] ] ]
核心解决方案:遍历与聚合
解决此类问题的核心思路是遍历目标数组,对其中的每个元素,在源数组中查找所有匹配的记录,并提取所需的属性进行聚合。PHP提供了一些内置函数,可以帮助我们高效地完成这一任务。
示例代码
以下代码展示了如何使用array_column和array_keys函数来实现上述数据合并:
<?php
// 原始数据:数组1 (lookup) 和 数组2 (db)
$lookup = [
["epid" => "123", "hash" => "xxxxxxA"],
["epid" => "456", "hash" => "xxxxxxB"],
["epid" => "789", "hash" => "xxxxxxC"],
["epid" => "123", "hash" => "xxxxxxD"],
["epid" => "123", "hash" => "xxxxxxE"],
];
$db = [
["epid" => "123", "name" => "This is a title"],
["epid" => "456", "name" => "This is a title"],
["epid" => "789", "name" => "This is a title"]
];
// 遍历目标数组 $db
foreach($db as $i => $el) {
// 步骤1: 使用 array_column 提取 $lookup 数组中所有 'epid' 列的值
// 步骤2: 使用 array_keys 查找哪些键的 'epid' 值与当前 $el["epid"] 匹配
$matchingKeys = array_keys(array_column($lookup, 'epid'), $el["epid"]);
// 遍历所有匹配的键,将对应的 'hash' 值添加到 $db 数组的当前元素中
foreach($matchingKeys as $key) {
// 如果 $db[$i]["hash"] 键不存在,它会在第一次赋值时自动创建为一个数组
$db[$i]["hash"][] = $lookup[$key]["hash"];
}
}
// 输出合并后的结果
echo "<pre>";
var_dump($db);
echo "</pre>";
?>
代码解析
- 初始化数组: $lookup 变量存储了源数据(数组1),$db 变量存储了目标数据(数组2)。
- 外层循环: foreach($db as $i => $el) 遍历 $db 数组的每个元素。$i 是当前元素的索引,$el 是当前元素的值(一个关联数组)。
-
查找匹配键:
- array_column($lookup, ‘epid’):这个函数会从 $lookup 数组中抽取所有子数组的 ‘epid’ 键对应的值,并返回一个新的一维数组。例如,它会生成 [“123”, “456”, “789”, “123”, “123”]。
- array_keys(…, $el[“epid”]):这个函数会在上一步生成的一维数组中查找所有值为 $el[“epid”] 的元素的键。这些键实际上对应着 $lookup 数组中匹配元素的原始索引。例如,当 $el[“epid”] 是 “123” 时,$matchingKeys 将会是 [0, 3, 4]。
-
内层循环聚合: foreach($matchingKeys as $key) 遍历所有找到的匹配键。
- $db[$i][“hash”][] = $lookup[$key][“hash”];:这行代码是实现聚合的关键。它通过 $key 访问 $lookup 数组中对应的元素,提取其 ‘hash’ 值,并将其添加到 $db 数组当前元素 ($db[$i]) 的 ‘hash’ 键下。
- 如果 $db[$i] 中还没有 ‘hash’ 键,PHP 会在第一次执行此操作时自动将其创建为一个空数组,然后将值添加进去。
- [] 语法确保每次添加都是作为新元素追加到数组的末尾。
- $db[$i][“hash”][] = $lookup[$key][“hash”];:这行代码是实现聚合的关键。它通过 $key 访问 $lookup 数组中对应的元素,提取其 ‘hash’ 值,并将其添加到 $db 数组当前元素 ($db[$i]) 的 ‘hash’ 键下。
这种方法简洁明了,利用了PHP内置函数的高效性,避免了手动编写复杂的嵌套循环来查找匹配项。
性能优化与注意事项
上述解决方案对于中小型数组是高效且可读的。然而,对于非常大的数组,每次外层循环都调用 array_column 和 array_keys 可能会导致性能瓶颈,因为 array_column 每次都会遍历整个 $lookup 数组。在这种情况下,我们可以通过预处理 $lookup 数组来构建一个查找表,从而显著提高性能。
优化方案:构建查找表
通过一次性遍历 $lookup 数组,我们可以创建一个以 epid 为键,以 hash 数组为值的查找表。这样,在遍历 $db 数组时,我们就可以通过 epid 直接进行 O(1)(平均时间复杂度)的查找。
<?php
// 原始数据:数组1 (lookup) 和 数组2 (db)
$lookup = [
["epid" => "123", "hash" => "xxxxxxA"],
["epid" => "456", "hash" => "xxxxxxB"],
["epid" => "789", "hash" => "xxxxxxC"],
["epid" => "123", "hash" => "xxxxxxD"],
["epid" => "123", "hash" => "xxxxxxE"],
];
$db = [
["epid" => "123", "name" => "This is a title"],
["epid" => "456", "name" => "This is a title"],
["epid" => "789", "name" => "This is a title"]
];
// 步骤1:预处理 $lookup 数组,构建以 epid 为键的查找表
$hashLookupMap = [];
foreach ($lookup as $item) {
$epid = $item['epid'];
$hash = $item['hash'];
// 如果该 epid 键不存在,则初始化为一个空数组
if (!isset($hashLookupMap[$epid])) {
$hashLookupMap[$epid] = [];
}
// 将 hash 值添加到对应的 epid 键下的数组中
$hashLookupMap[$epid][] = $hash;
}
// 步骤2:遍历 $db 数组,利用查找表合并数据
foreach ($db as $i => $el) {
$epid = $el['epid'];
// 检查查找表中是否存在当前 epid
if (isset($hashLookupMap[$epid])) {
$db[$i]['hash'] = $hashLookupMap[$epid];
} else {
// 可选:如果 $db 中的 epid 在 $lookup 中没有匹配项,
// 可以选择添加一个空数组,或者不添加 'hash' 键
// $db[$i]['hash'] = [];
}
}
// 输出合并后的结果
echo "<pre>";
var_dump($db);
echo "</pre>";
?>
其他注意事项
- 数据类型一致性: 确保用于匹配的键(如 epid)在两个数组中的数据类型是一致的(例如,都是字符串或都是整数),以避免意外的比较结果。
- 内存使用: 对于包含数百万条记录的超大型数组,即使是优化后的查找表方法也可能消耗大量内存。在这种极端情况下,可能需要考虑分批处理数据,或者利用数据库的连接和聚合功能来完成任务。
- epid 不存在的情况: 在优化方案中,如果 $db 数组中的某个 epid 在 $hashLookupMap 中没有对应的键,则 $db[$i][‘hash’] 将不会被设置。根据业务需求,您可能希望在这种情况下显式地将其设置为一个空数组 [],如代码注释所示。
总结
本教程详细介绍了如何在PHP中将一个数组中基于共同标识符的重复属性聚合到另一个目标数组中。我们提供了两种实现方案:
- 基于 array_column 和 array_keys 的方案: 适用于中小型数组,代码简洁,易于理解。
- 基于预构建查找表的优化方案: 适用于大型数组,通过一次性预处理源数据,显著提高了查找效率,降低了整体时间复杂度。
选择哪种方案取决于您的具体应用场景和数据规模。理解这些数组操作技巧,将有助于您更高效、更灵活地处理PHP中的数据整合任务。
以上就是PHP数组深度合并:按ID聚合多重属性的详细内容,更多请关注php中文网其它相关文章!


