You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归扁平化含嵌套列表的Python字典出错,求问题定位

字典嵌套列表规范化的递归逻辑问题分析

问题背景

需要将包含嵌套列表的Python字典规范化,让每个列表元素生成一条完整的扁平化记录。

测试字典

test_dict = {
    'name' : 'john',
    'age' : 20,
    'addresses' : [
        {
            'street': 'XXX',
            'number': 123,
            'complement' : [
                'HOUSE',
                'NEAR MARKET'
            ]
        },
        {
            'street': 'YYY',
            'number': 456,
            'complement' : [
                'AP',
                'NEAR PARK'
            ]
        },
    ],
    'phones' : [
        '123456'
    ],
    'gender' : 'MASC'
}

期望输出

{'name': 'john', 'age': 20, 'street': 'XXX', 'number': 123, 'complement': 'HOUSE', 'phones': '123456', 'gender' : 'MASC'}
{'name': 'john', 'age': 20, 'street': 'XXX', 'number': 123, 'complement': 'NEAR MARKET', 'phones': '123456', 'gender' : 'MASC'}
{'name': 'john', 'age': 20, 'street': 'YYY', 'number': 456, 'complement': 'AP', 'phones': '123456', 'gender' : 'MASC'}
{'name': 'john', 'age': 20, 'street': 'YYY', 'number': 456, 'complement': 'NEAR PARK', 'phones': '123456', 'gender' : 'MASC'}

实际输出(原代码运行结果)

{'name': 'john', 'age': 20, 'street': 'XXX', 'number': 123, 'complement': 'HOUSE'}
{'name': 'john', 'age': 20, 'street': 'XXX', 'number': 123, 'complement': 'NEAR MARKET'}
{'name': 'john', 'age': 20, 'street': 'YYY', 'number': 456, 'complement': 'AP'}
{'name': 'john', 'age': 20, 'street': 'YYY', 'number': 456, 'complement': 'NEAR PARK'}
{'name': 'john', 'age': 20, 'phones': '123456'}

原递归代码

def get_list_values(lista, dicionario, key_name, results):
    if len(lista) > 0:
        for l in lista:
            if isinstance(l, dict):
                search_values(l, dicionario.copy(), results)
            else:
                dicionario_metodo = dicionario.copy()
                dicionario_metodo[key_name] = l
                results.append(dicionario_metodo)

def search_values(dicionario, test, results):
    for k, v in dicionario.items():
        if isinstance(v, list):
            get_list_values(v, test, k, results )
        else: 
            test[k] = v
    if not any(isinstance(v, list) for v in dicionario.values()):
        results.append(test.copy())
    return results 


test = {}
results = []
for r in search_values(test_dict, test, results):
    print(r)

递归逻辑错误分析

  • 字段处理中断:当遇到列表类型的字段时,直接跳转到get_list_values处理,但没有继续处理当前字典的后续字段(比如phones、gender),导致这些字段无法被合并到列表展开后的记录中。
  • 列表独立处理:代码将phones这类顶层列表单独展开成记录,而没有和其他列表(如addresses展开后的记录)做笛卡尔积合并,生成了孤立的不完整记录。
  • 上下文传递缺失:递归处理嵌套字典时,没有传递父级字典中已经收集到的所有非列表字段,逻辑上存在漏洞,仅在当前测试场景下碰巧保留了部分顶层字段。

修正后的实现

核心思路:先递归扁平化嵌套字典,分离固定字段与列表字段,再通过笛卡尔积生成所有列表元素的组合,最后将每个组合与固定字段合并为完整记录。

def flatten_dict(data, parent_key='', sep='_'):
    """递归扁平化嵌套字典,保留列表字段"""
    items = []
    for k, v in data.items():
        new_key = f"{parent_key}{sep}{k}" if parent_key else k
        if isinstance(v, dict):
            items.extend(flatten_dict(v, new_key, sep).items())
        elif isinstance(v, list):
            items.append((new_key, v))
        else:
            items.append((new_key, v))
    return dict(items)

def generate_records(data):
    """生成所有笛卡尔积组合的扁平化记录"""
    flat_data = flatten_dict(data)
    # 分离固定字段和列表字段
    fixed_fields = {k: v for k, v in flat_data.items() if not isinstance(v, list)}
    list_fields = {k: v for k, v in flat_data.items() if isinstance(v, list)}
    
    # 计算所有列表字段的笛卡尔积
    from itertools import product
    keys = list(list_fields.keys())
    value_lists = list(list_fields.values())
    
    records = []
    for combo in product(*value_lists):
        record = fixed_fields.copy()
        record.update(dict(zip(keys, combo)))
        records.append(record)
    return records

# 测试基础用例
test_dict = {
    'name' : 'john',
    'age' : 20,
    'addresses' : [
        {
            'street': 'XXX',
            'number': 123,
            'complement' : [
                'HOUSE',
                'NEAR MARKET'
            ]
        },
        {
            'street': 'YYY',
            'number': 456,
            'complement' : [
                'AP',
                'NEAR PARK'
            ]
        },
    ],
    'phones' : [
        '123456'
    ],
    'gender' : 'MASC'
}

print("基础用例输出:")
for record in generate_records(test_dict):
    print(record)

# 测试更复杂的用例
complex_test_dict = {
    'name' : 'john',
    'age' : 20,
    'addresses' : [
        {
            'street': 'XXX',
            'number': 123,
            'complement' : [
                'HOUSE',
                'NEAR MARKET'
            ]
        },
        {
            'street': 'YYY',
            'number': 456,
            'complement' : [
                'AP',
                'NEAR PARK'
            ]
        },
    ],
    'type' : {
        'category': 'G123',
        'products': [
            'test1',
            'test2'
        ]
    },
    'phones' : [
        '123456'
    ],
    'gender' : 'MASC'
}

print("\n复杂用例输出:")
for record in generate_records(complex_test_dict):
    print(record)

修正后基础用例输出

{'name': 'john', 'age': 20, 'gender': 'MASC', 'addresses_street': 'XXX', 'addresses_number': 123, 'addresses_complement': 'HOUSE', 'phones': '123456'}
{'name': 'john', 'age': 20, 'gender': 'MASC', 'addresses_street': 'XXX', 'addresses_number': 123, 'addresses_complement': 'NEAR MARKET', 'phones': '123456'}
{'name': 'john', 'age': 20, 'gender': 'MASC', 'addresses_street': 'YYY', 'addresses_number': 456, 'addresses_complement': 'AP', 'phones': '123456'}
{'name': 'john', 'age': 20, 'gender': 'MASC', 'addresses_street': 'YYY', 'addresses_number': 456, 'addresses_complement': 'NEAR PARK', 'phones': '123456'}

复杂用例输出说明

会生成2(地址)*2(地址补充)*2(产品)*1(电话)=8条完整记录,每条记录包含所有字段:name、age、gender、addresses_street、addresses_number、addresses_complement、type_category、type_products、phones。


内容的提问来源于stack exchange,提问作者CooperativistKid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:55:53