当从数据库查询出包含重复标识的数据后,我们可以通过PHP的数组操作技巧,将重复项的数据聚合到同一个数组元素中,让数据结构更符合业务需求。

场景示例
假设我们从数据库查询出了用户的订单列表,原始查询结果如下,同一个用户可能有多个订单,用户ID是重复的:
$origin_data = [
['user_id' => 1, 'order_id' => 101, 'amount' => 99.9],
['user_id' => 1, 'order_id' => 102, 'amount' => 199.9],
['user_id' => 2, 'order_id' => 103, 'amount' => 299.9],
['user_id' => 2, 'order_id' => 104, 'amount' => 399.9],
['user_id' => 3, 'order_id' => 105, 'amount' => 499.9],
];方法一:使用循环手动聚合
通过遍历原始数组,以重复的标识字段作为新数组的键,将重复项的数据合并到对应键的数组中,是最基础也最容易理解的方法。
$result = [];
foreach ($origin_data as $item) {
$user_id = $item['user_id'];
// 如果当前用户ID对应的键不存在,先初始化数组
if (!isset($result[$user_id])) {
$result[$user_id] = [
'user_id' => $user_id,
'order_list' => [],
'total_amount' => 0
];
}
// 将订单信息加入订单列表
$result[$user_id]['order_list'][] = [
'order_id' => $item['order_id'],
'amount' => $item['amount']
];
// 累加总金额
$result[$user_id]['total_amount'] += $item['amount'];
}
// 如果需要重置索引,可以使用array_values函数
$final_result = array_values($result);
print_r($final_result);方法二:使用array_reduce函数聚合
array_reduce函数可以对数组中的元素依次回调处理,适合用来做数组的重构和聚合操作,代码会更简洁。
$result = array_reduce($origin_data, function ($carry, $item) {
$user_id = $item['user_id'];
if (!isset($carry[$user_id])) {
$carry[$user_id] = [
'user_id' => $user_id,
'order_list' => [],
'total_amount' => 0
];
}
$carry[$user_id]['order_list'][] = [
'order_id' => $item['order_id'],
'amount' => $item['amount']
];
$carry[$user_id]['total_amount'] += $item['amount'];
return $carry;
}, []);
$final_result = array_values($result);
print_r($final_result);聚合后的数据结构
以上两种方法最终得到的$final_result结构如下,同一个用户的订单都被聚合到了同一个元素中:
Array
(
[0] => Array
(
[user_id] => 1
[order_list] => Array
(
[0] => Array
(
[order_id] => 101
[amount] => 99.9
)
[1] => Array
(
[order_id] => 102
[amount] => 199.9
)
)
[total_amount] => 299.8
)
[1] => Array
(
[user_id] => 2
[order_list] => Array
(
[0] => Array
(
[order_id] => 103
[amount] => 299.9
)
[1] => Array
(
[order_id] => 104
[amount] => 399.9
)
)
[total_amount] => 699.8
)
[2] => Array
(
[user_id] => 3
[order_list] => Array
(
[0] => Array
(
[order_id] => 105
[amount] => 499.9
)
)
[total_amount] => 499.9
)
)注意事项
- 聚合时作为键的字段要确保唯一性,避免出现意外的键覆盖问题。
- 如果原始数据量较大,循环方法的性能会更稳定,复杂函数调用可能会带来额外的性能开销。
- 聚合后的数组如果需要保持原有顺序,可以在初始化键的时候记录顺序,最后再按顺序排列。