PHP嵌套repeat数组转换:为元素添加正确repeat计数属性
问题:处理嵌套repeat/close_repeat数组的转换
需求说明
现有数组A包含repeat和close_repeat类型的特殊对象:
repeat对象带有number属性,指定其与对应close_repeat之间元素的重复次数- 支持嵌套结构,嵌套时重复次数为各层
number的乘积
需要将数组A转换为数组B:
- 移除所有
repeat和close_repeat对象 - 为其余元素添加
repeat属性,标记该元素应重复的次数(例如示例中id为8的元素repeat值为3*2=6)
示例数组
Array A
[ { "id":1, "type":"title", "data": "Title goes here" }, { "id":2, "type":"repeat", "number":3 }, { "id":3, "type":"media", "data": "path to media" }, { "id":4, "type":"close_repeat" }, { "id":5, "type":"repeat", "number":3 }, { "id":6, "type":"title", "data": "Title goes here" }, { "id":7, "type":"repeat", "number":2 }, { "id":8, "type":"text", "data": "Text goes here" }, { "id":9, "type":"close_repeat" }, { "id":10, "type":"close_repeat" }, { "id":11, "type":"cover", "data": "Cover data goes here" } ]
Array B
[ { "id":1, "type":"title", "data": "Title goes here", "repeat":1 }, { "id":3, "type":"media", "data": "path to media", "repeat":1 }, { "id":6, "type":"title", "data": "Title goes here", "repeat":3 }, { "id":8, "type":"text", "data": "Text goes here", "repeat":6 }, { "id":11, "type":"cover", "data": "Cover data goes here", "repeat":1 } ]
现有尝试代码(存在问题)
public function loopOver($data, &$newData, &$repeat, &$previousRepeat, $i){ $dataCount = count($data); for( ; $i<$dataCount; $i++){ if($data[$i]['type']=='repeat'){ $previousRepeat = $data[$i]['number']; $repeat = $repeat * $data[$i]['number']; return $this->loopOver($data, $newData, $repeat, $previousRepeat, $i+1); } if($data[$i]['type']=='close_repeat'){ $repeat = $repeat/$previousRepeat; return $this->loopOver($data, $newData, $repeat, $previousRepeat, $i+1); } if($i >= $dataCount){ return $newData; } $tmpData = $data[$i]; $tmpData['repeat'] = $repeat; $newData [] = $tmpData; } }
问题分析
原代码的核心问题:
- 使用单个
previousRepeat变量保存上一层的重复次数,嵌套时会被覆盖,导致回溯计算错误 - 递归中使用
return会中断当前循环,后续元素无法继续处理 - 依赖引用传递维护状态,逻辑容易混乱
正确解决方案
使用栈结构来维护嵌套的重复次数上下文,栈的先进后出特性完美匹配嵌套结构的层级关系:
public function processRepeatArray($data) { $newData = []; $repeatStack = [1]; // 栈保存每一层进入repeat前的重复次数,初始默认1 $currentRepeat = 1; foreach ($data as $item) { switch ($item['type']) { case 'repeat': // 进入新的repeat层,先保存当前重复次数到栈 array_push($repeatStack, $currentRepeat); // 更新当前重复次数为乘积 $currentRepeat *= $item['number']; break; case 'close_repeat': // 退出repeat层,恢复到上一层的重复次数 $currentRepeat = array_pop($repeatStack); break; default: // 普通元素,添加当前重复次数属性 $newItem = $item; $newItem['repeat'] = $currentRepeat; $newData[] = $newItem; break; } } return $newData; }
逻辑说明
- 初始时
currentRepeat为1,栈中默认存入1,对应最外层无重复的情况 - 遇到
repeat时:将当前的currentRepeat压入栈,然后将currentRepeat乘以当前repeat的number,进入嵌套层 - 遇到
close_repeat时:弹出栈顶的数值,赋值给currentRepeat,回到上一层的重复次数状态 - 普通元素直接添加
repeat属性为当前的currentRepeat,加入结果数组
这个方案能正确处理任意深度的嵌套结构,计算出准确的重复次数。
内容的提问来源于stack exchange,提问作者lari107k
相关产品推荐
相关产品推荐

