
本文介绍一种递归方法,用于遍历具有多级嵌套结构(支持 child 或 children 键)的问卷字典,并生成所有合法的选择路径组合,每个组合以嵌套对象形式呈现,适用于动态表单、用户画像构建或测试用例生成等场景。
本文介绍一种递归方法,用于遍历具有多级嵌套结构(支持 `child` 或 `children` 键)的问卷字典,并生成所有合法的选择路径组合,每个组合以嵌套对象形式呈现,适用于动态表单、用户画像构建或测试用例生成等场景。
在构建动态问卷系统、A/B 测试配置或用户分群逻辑时,常需枚举所有可能的回答路径。给定一个层级化字典结构(如 question + choices + 可选的 child 或 children 子节点),目标是生成所有深度优先的完整选择链,每条链对应一个用户可能提交的完整答案序列。
关键挑战在于:
- 字典结构不统一(子节点键名可能是 "child" 或 "children");
- 每层仅有一个 choice 值被选中,但需与下层所有可能性笛卡尔组合;
- 最终结果需保持嵌套结构,而非扁平列表。
以下是一个健壮、可读性强的递归实现:
def generate_combinations(question_dict):
"""
生成嵌套问卷字典中所有可能的选择组合。
Args:
question_dict (dict): 包含 'choices' 的层级字典,可选 'child' 或 'children' 键
Returns:
list: 每个元素为一个嵌套字典,表示一条完整选择路径
"""
def _recurse(node, path=None):
if path is None:
path = {}
# 当前层必须有 choices,否则无效节点
if "choices" not in node:
return [path] if path else []
results = []
for choice in node["choices"]:
# 构建当前层级的对象:{"choice": "..."}
current_node = {"choice": choice}
# 初始化子路径(若存在子节点)
child_path = {}
# 兼容 'child' 和 'children' 两种键名
if "child" in node and isinstance(node["child"], dict):
child_node = node["child"]
child_key = "child"
elif "children" in node and isinstance(node["children"], dict):
child_node = node["children"]
child_key = "child" # 统一使用 'child' 作为输出键名
else:
# 无子节点 → 当前路径即为完整组合
results.append({**path, **current_node})
continue
# 递归处理子节点,并将结果挂载到 current_node 下
child_combinations = _recurse(child_node, {})
for child_combo in child_combinations:
# 合并:当前层 choice + 子层嵌套结构
full_combo = {**current_node, child_key: child_combo}
if path: # 若有上级路径,合并到顶层
results.append({**path, **full_combo})
else:
results.append(full_combo)
return results
return _recurse(question_dict)✅ 使用示例:
data = {
"question": "Gender?",
"choices": ["Male", "Female", "Non Bynary", "Other"],
"child": {
"question": "Country?",
"choices": ["USA", "Canada", "France", "Other"],
"children": {
"question": "Age?",
"choices": ["<20", "20-30", "30-40", "40+"],
}
}
}
combinations = generate_combinations(data)
print(f"共生成 {len(combinations)} 种组合")
# 输出前两条示例:
print(combinations[0])
# {'choice': 'Male', 'child': {'choice': 'USA', 'child': {'choice': '<20'}}}
print(combinations[1])
# {'choice': 'Male', 'child': {'choice': 'USA', 'child': {'choice': '20-30'}}}⚠️ 注意事项:
- 该函数不依赖 itertools.product,避免因结构不规则导致的 AttributeError: 'str' object has no attribute 'values';
- 显式区分 "child"(单个子节点)和 "children"(历史兼容字段),并在输出中统一使用 "child" 键名,确保结果结构一致;
- 时间复杂度为各层 choices 长度的乘积(即笛卡尔积规模),对超深或超宽结构请评估内存开销;
- 若需支持“跳过某题”或“多选”语义,需扩展 choices 类型(如支持列表值)并修改递归逻辑。
通过此方案,你可稳定、清晰地将任意深度的问卷树展开为完整回答路径集合,为后续分析、模拟或验证提供结构化输入基础。

















