如何将商品变体选择集转换为符合规则的有序optionTree数组结构
实现思路
- 先定义所有维度的可选值列表,顺序对应optionTree每一层的数组下标
- 生成每个维度的可选值到下标的映射表,方便快速把选择项的字符串转为数组下标
- 递归初始化全0的多维度数组作为初始optionTree,维度数量、每一层长度和定义的维度完全匹配
- 遍历所有待插入商品,沿着选择项对应的下标逐层遍历optionTree,最后把最深处的位置的值替换为对应商品ID
PHP 实现代码
<?php // 定义所有维度的可选值,顺序对应optionTree的层级 $dimensions = [ ['red', 'green', 'blue'], // 第一层:颜色 ['small', 'medium', 'large'], // 第二层:尺码 ['brandX', 'brandY'] // 第三层:品牌 ]; // 待插入的商品数组 $products_to_add = [ [ "choices" => ['red', 'medium', 'brandX'], "product_id" => 820 ], [ "choices" => ['red', 'small', 'brandY'], "product_id" => 821 ], [ "choices" => ['green', 'small', 'brandX'], "product_id" => 822 ], [ "choices" => ['blue', 'large', 'brandY'], "product_id" => 823 ], ]; // 递归初始化全0的optionTree function initTree(array $dimensions, int $currentDim = 0): array { $layerSize = count($dimensions[$currentDim]); $tree = array_fill(0, $layerSize, 0); // 非最后一层,继续初始化下一层 if ($currentDim < count($dimensions) - 1) { foreach ($tree as $index => $value) { $tree[$index] = initTree($dimensions, $currentDim + 1); } } return $tree; } // 生成每个维度的值到下标的映射表 $dimMaps = []; foreach ($dimensions as $dimIndex => $dimValues) { $dimMaps[$dimIndex] = array_flip($dimValues); } // 初始化树 $optionTree = initTree($dimensions); // 插入所有商品 foreach ($products_to_add as $product) { $choices = $product['choices']; $productId = $product['product_id']; $currentLayer = &$optionTree; foreach ($choices as $dimIndex => $choiceVal) { $pos = $dimMaps[$dimIndex][$choiceVal]; // 到达最后一层,赋值商品ID if ($dimIndex === count($choices) - 1) { $currentLayer[$pos] = $productId; break; } // 移动到下一层 $currentLayer = &$currentLayer[$pos]; } unset($currentLayer); // 解除引用避免污染 } // 输出结果 var_dump(json_encode($optionTree)); ?>
JavaScript 实现代码
// 定义所有维度的可选值,顺序对应optionTree的层级 const dimensions = [ ['red', 'green', 'blue'], // 第一层:颜色 ['small', 'medium', 'large'], // 第二层:尺码 ['brandX', 'brandY'] // 第三层:品牌 ]; // 待插入的商品数组 const productsToAdd = [ { choices: ['red', 'medium', 'brandX'], product_id: 820 }, { choices: ['red', 'small', 'brandY'], product_id: 821 }, { choices: ['green', 'small', 'brandX'], product_id: 822 }, { choices: ['blue', 'large', 'brandY'], product_id: 823 } ]; // 递归初始化全0的optionTree function initTree(dimensions, currentDim = 0) { const layerSize = dimensions[currentDim].length; const tree = new Array(layerSize).fill(0); // 非最后一层,继续初始化下一层 if (currentDim < dimensions.length - 1) { for (let i = 0; i < layerSize; i++) { tree[i] = initTree(dimensions, currentDim + 1); } } return tree; } // 生成每个维度的值到下标的映射表 const dimMaps = dimensions.map(dimValues => { return dimValues.reduce((map, val, index) => { map[val] = index; return map; }, {}); }); // 初始化树 const optionTree = initTree(dimensions); // 插入所有商品 productsToAdd.forEach(product => { const { choices, product_id: productId } = product; let currentLayer = optionTree; choices.forEach((choiceVal, dimIndex) => { const pos = dimMaps[dimIndex][choiceVal]; // 到达最后一层,赋值商品ID if (dimIndex === choices.length - 1) { currentLayer[pos] = productId; return; } // 移动到下一层 currentLayer = currentLayer[pos]; }); }); // 输出结果 console.log(JSON.stringify(optionTree));
输出结果示例
运行代码后得到的optionTree结构如下:
[ [[0,821],[820,0],[0,0]], [[822,0],[0,0],[0,0]], [[0,0],[0,0],[0,823]] ]
完全符合规则要求,且支持任意数量的维度扩展,只需要修改dimensions数组的内容即可,不需要调整核心逻辑。
内容的提问来源于stack exchange,提问作者DiscreteTomatoes
相关产品推荐
相关产品推荐

