能否将数据库返回的扁平数组转换为带动态键的多维数组?求实现方向指引
当然可行!这种多层分组嵌套的需求其实挺常见的,递归或者迭代的方式都能搞定,我给你拆解下具体的实现思路和步骤:
实现思路指引
核心逻辑:按分组键层级逐步构建树形结构
我们的目标是把扁平化的数据库返回数据,按照给定的分组键数组(比如["sm__state_name__", "om__order_date__year", ...])一层一层嵌套成你要的树形结构,每一层都要维护key、子节点items、当前层级的count和summary。
1. 初始化根容器
首先创建一个根容器来存放最终的data数组,同时准备好统计总数量的变量totalCount。
2. 遍历每条原始数据
对于每一条数据库返回的记录,我们需要沿着分组键的层级,一步步找到对应的节点:
- 从根节点的
data开始,依次使用当前分组键的值(比如第一条记录的Luanda、2017、3、8)作为key,检查当前层级的items里是否已经存在这个key的节点。 - 如果不存在,就创建一个新的节点,包含
key、空的items(最后一层设为null)、初始的count和summary。 - 如果已经存在,就更新该节点的
count(累加当前记录的count1)和summary(累加当前记录的sum1)。
3. 递归/迭代处理层级嵌套
这里推荐递归实现,因为分组键的数量不固定,递归可以灵活适配任意层级的分组:
- 写一个递归函数,参数包括当前处理的分组键索引、当前层级的父节点、当前记录的数据。
- 当处理到最后一个分组键时,直接创建叶子节点(
items: null),并设置对应的count和summary。 - 当不是最后一层时,找到或创建当前键对应的子节点,然后递归处理下一个分组键。
4. 计算各层级的汇总值
每一层的summary和count需要是其子节点的累加值,你可以在创建节点的时候实时累加父节点的数值(效率更高),也可以在构建完所有叶子节点后,递归从下往上汇总。
代码示例(PHP实现,适配你给出的数组格式)
function buildNestedTree(array $rawData, array $groupKeys): array { $root = ['data' => [], 'totalCount' => 0]; foreach ($rawData as $item) { $currentLevel = &$root['data']; $currentCount = (int)$item['count1']; $currentSum = (float)$item['sum1']; // 遍历分组键,逐层构建节点 for ($i = 0; $i < count($groupKeys); $i++) { $key = $item[$groupKeys[$i]]; // 处理null值,避免分组异常 if ($key === null) $key = 'Unknown'; // 快速查找当前层级是否已有该key的节点 $nodeExists = false; $nodeIndex = 0; foreach ($currentLevel as $idx => $node) { if ($node['key'] == $key) { $nodeExists = true; $nodeIndex = $idx; break; } } if (!$nodeExists) { // 创建新节点 $newNode = [ 'key' => $key, 'items' => $i === count($groupKeys) - 1 ? null : [], 'count' => $i === count($groupKeys) - 1 ? $currentCount : 0, 'summary' => $i === count($groupKeys) - 1 ? [$currentSum] : [0.0] ]; $currentLevel[] = $newNode; $nodeIndex = count($currentLevel) - 1; } else { // 更新叶子节点的数值 if ($i === count($groupKeys) - 1) { $currentLevel[$nodeIndex]['count'] += $currentCount; $currentLevel[$nodeIndex]['summary'][0] += $currentSum; } } // 累加父节点的count和summary if ($i !== count($groupKeys) - 1) { $currentLevel[$nodeIndex]['count'] += $currentCount; $currentLevel[$nodeIndex]['summary'][0] += $currentSum; } // 移动到下一层级继续处理 if ($i !== count($groupKeys) - 1) { $currentLevel = &$currentLevel[$nodeIndex]['items']; } } // 累加总数量 $root['totalCount'] += $currentCount; } return $root; } // 使用示例 $rawData = [ ['sum1' => '5645000', 'count1' => '4', 'sm__state_name__' => 'Luanda', 'om__order_date__year' => '2017', 'om__order_date__quarter' => '3', 'om__order_date__month' => '8'], ['sum1' => '213985939.8600001', 'count1' => '1606', 'sm__state_name__' => 'Luanda', 'om__order_date__year' => '2017', 'om__order_date__quarter' => '3', 'om__order_date__month' => '9'], // 其他记录可以继续添加 ]; $groupKeys = ["sm__state_name__", "om__order_date__year", "om__order_date__quarter", "om__order_date__month"]; $result = buildNestedTree($rawData, $groupKeys); echo json_encode($result, JSON_PRETTY_PRINT);
注意事项
- 处理
null值:如果分组键对应的值为null(比如示例中的某条记录sm__state_name__为null),可以统一替换为"Unknown"或者其他标识,避免出现分组异常。 - 数值类型转换:数据库返回的
sum1和count1通常是字符串,需要转换成对应的数值类型(float/int)再进行累加,否则会出现字符串拼接的错误。 - 性能优化:如果数据量很大,遍历查找节点的方式效率较低,可以改用哈希表(比如用
key作为数组的键)来快速定位节点,减少循环次数。
内容的提问来源于stack exchange,提问作者Vivek Makwana
相关产品推荐
相关产品推荐

