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

Python:合并带点分隔键的嵌套字典并输出JSON的问题

元数据合并问题解决方案

数据结构介绍

从扫描电镜(SEM)采集数据中提取三类元数据:

  • acquisitionMetadata:普通字典,键为点分隔字符串,代表层级结构
  • datasetMetadata:同结构字典的列表,每个字典对应一个采集任务的数据集元数据
  • imageMetadata:字典列表,每个元素对应一个数据集,且包含另一个字典列表,代表该数据集下每张图片的元数据

需求说明

需要在Python中将三类字典合并为嵌套字典(最终输出为JSON文件),键代表层级关系。例如'acquisition.dataset.images.creationTime': '18.08.2020 17:51:07'需转换为以下嵌套结构:

acquisition {
    dataset {
        images {
            creationTime: '18.08.2020 17:51:07'
        }
    }
}

问题

现有代码无法正确生成dataset和images数组,要么重复已存在的acquisition、dataset、image键,要么将图片字典放在数据集数组外。AI生成的代码存在硬编码层级问题,输出有冗余键。

期望输出结构

合并后的字典需符合如下嵌套结构:

metadata = {
    'acquisition': {
        'genericMetadata': {
            'program': {
                'programName': 'Auto Slice & View 4',
                'programVersion': '4.2.1.1982'
            },
            'applicationId': {
                'identifierValue': 'ASV'
            },
            'fileVersion': '1.2',
            'projectName': '20200818_AlSi13 XRM tomo2',
            'numberOfCuts': '719'
        },
        'dataset': [
            {
                'rows': '1',
                'columns': '1',
                'images': [
                    {
                        'creationTime': '18.08.2020 17:51:07',
                        'stage': {
                            'workingDistance': {
                                'value': '0.00403678'
                            }
                        }
                    },
                    {
                        'creationTime': '18.08.2020 18:09:06',
                        'stage': {
                            'workingDistance': {
                                'value': '0.00403773'
                            }
                        }
                    }
                ]
            },
            {
                'rows': '1',
                'columns': '1',
                'images': [
                    {
                        'creationTime': '18.08.2020 17:51:07',
                        'stage': {
                            'workingDistance': {
                                'value': '0.00403678'
                            }
                        }
                    },
                    {
                        'creationTime': '18.08.2020 18:09:06',
                        'stage': {
                            'workingDistance': {
                                'value': '0.00403773'
                            }
                        }
                    }
                ]
            }
        ]
    }
}

最小可复现输入

acquisition_metadata = {
    'acquisition.genericMetadata.program.programName': 'Auto Slice & View 4',
    'acquisition.genericMetadata.program.programVersion': '4.2.1.1982',
    'acquisition.genericMetadata.applicationId.identifierValue': 'ASV',
    'acquisition.genericMetadata.fileVersion': '1.2',
    'acquisition.genericMetadata.projectName': '20200818_AlSi13 XRM tomo2',
    'acquisition.genericMetadata.numberOfCuts': '719',
}

dataset_metadata = [
    {
        'acquisition.dataset.rows': '1',
        'acquisition.dataset.columns': '1',
    },
    {
        'acquisition.dataset.rows': '1',
        'acquisition.dataset.columns': '1',
    },
]

image_metadata = [
    [
        {
            'acquisition.dataset.images.creationTime': '18.08.2020 17:51:07',
            'acquisition.dataset.images.stage.workingDistance.value': '0.00403678',
        },
        {
            'acquisition.dataset.images.creationTime': '18.08.2020 18:09:06',
            'acquisition.dataset.images.stage.workingDistance.value': '0.00403773',
        }
    ],
    [
        {
            'acquisition.dataset.images.creationTime': '18.08.2020 17:51:07',
            'acquisition.dataset.images.stage.workingDistance.value': '0.00403678',
        },
        {
            'acquisition.dataset.images.creationTime': '18.08.2020 18:09:06',
            'acquisition.dataset.images.stage.workingDistance.value': '0.00403773',
        }
    ]
]

已尝试代码(存在冗余键问题)

import json
import os

def combine_metadata(acquisition_metadata, dataset_metadata, image_metadata):
    metadata = {}
    
    # Combine acquisition metadata
    for key, value in acquisition_metadata.items():
        nested_keys = key.split('.')
        current_dict = metadata
        
        for nested_key in nested_keys[:-1]:
            if nested_key not in current_dict:
                current_dict[nested_key] = {}
            current_dict = current_dict[nested_key]
        
        current_dict[nested_keys[-1]] = value
    
    # Combine dataset metadata
    metadata['acquisition']['dataset'] = []
    for dataset in dataset_metadata:
        dataset_dict = {}
        for key, value in dataset.items():
            nested_keys = key.split('.')
            current_dict = dataset_dict
            
            for nested_key in nested_keys[:-1]:
                if nested_key not in current_dict:
                    current_dict[nested_key] = {}
                current_dict = current_dict[nested_key]
            
            current_dict[nested_keys[-1]] = value
        
        metadata['acquisition']['dataset'].append(dataset_dict)
    
    # Combine image metadata
    for i, images in enumerate(image_metadata):
        metadata['acquisition']['dataset'][i]['images'] = []
        for image in images:
            image_dict = {}
            for key, value in image.items():
                nested_keys = key.split('.')
                current_dict = image_dict
                
                for nested_key in nested_keys[:-1]:
                    if nested_key not in current_dict:
                        current_dict[nested_key] = {}
                    current_dict = current_dict[nested_key]
                
                current_dict[nested_keys[-1]] = value
            
            metadata['acquisition']['dataset'][i]['images'].append(image_dict)
    
    return metadata

def save_metadata_as_json(metadata, save_path):
    filename = os.path.join(save_path, "combined.json")
    with open(filename, 'w') as file:
        json.dump(metadata, file, indent=4)
    print(f"Metadata saved as {filename}")

问题输出示例

{
    "acquisition": {
        "genericMetadata": {
            "program": {
                "programName": "Auto Slice & View 4",
                "programVersion": "4.2.1.1982"
            },
            "applicationId": {
                "identifierValue": "ASV"
            },
            "fileVersion": "1.2",
            "projectName": "20200818_AlSi13 XRM tomo2",
            "numberOfCuts": "719"
        },
        "dataset": [
            {
                "acquisition": {
                    "dataset": {
                        "rows": "1",
                        "columns": "1"
                    }
                },
                "images": [
                    {
                        "acquisition": {
                            "dataset": {
                                "images": {
                                    "creationTime": "18.08.2020 17:51:07",
                                    "stage": {
                                        "workingDistance": {
                                            "value": "0.00403678"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    {
                        "acquisition": {
                            "dataset": {
                                "images": {
                                    "creationTime": "18.08.2020 18:09:06",
                                    "stage": {
                                        "workingDistance": {
                                            "value": "0.00403773"
                                        }
                                    }
                                }
                            }
                        }
                    }
                ]
            },
            {
                "acquisition": {
                    "dataset": {
                        "rows": "1",
                        "columns": "1"
                    }
                },
                "images": [
                    {
                        "acquisition": {
                            "dataset": {
                                "images": {
                                    "creationTime": "18.08.2020 17:51:07",
                                    "stage": {
                                        "workingDistance": {
                                            "value": "0.00403678"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    {
                        "acquisition": {
                            "dataset": {
                                "images": {
                                    "creationTime": "18.08.2020 18:09:06",
                                    "stage": {
                                        "workingDistance": {
                                            "value": "0.00403773"
                                        }
                                    }
                                }
                            }
                        }
                    }
                ]
            }
        ]
    }
}

修正后的代码

核心思路是处理dataset和image的键时,忽略前缀的acquisition.dataset或acquisition.dataset.images,直接解析剩余的层级路径:

import json
import os

def parse_nested_key(key, prefix):
    """去除键的指定前缀,返回剩余的层级键列表"""
    if key.startswith(prefix):
        return key[len(prefix)+1:].split('.')
    return key.split('.')

def build_nested_dict(flat_dict, prefix=""):
    """将扁平化字典转换为嵌套字典,可指定要忽略的前缀"""
    nested_dict = {}
    for key, value in flat_dict.items():
        keys = parse_nested_key(key, prefix)
        current = nested_dict
        for k in keys[:-1]:
            if k not in current:
                current[k] = {}
            current = current[k]
        current[keys[-1]] = value
    return nested_dict

def combine_metadata(acquisition_metadata, dataset_metadata, image_metadata):
    metadata = build_nested_dict(acquisition_metadata)
    
    # 处理dataset列表
    metadata['acquisition']['dataset'] = []
    for ds in dataset_metadata:
        ds_dict = build_nested_dict(ds, prefix="acquisition.dataset")
        metadata['acquisition']['dataset'].append(ds_dict)
    
    # 处理image列表,与dataset一一对应
    for i, img_list in enumerate(image_metadata):
        metadata['acquisition']['dataset'][i]['images'] = []
        for img in img_list:
            img_dict = build_nested_dict(img, prefix="acquisition.dataset.images")
            metadata['acquisition']['dataset'][i]['images'].append(img_dict)
    
    return metadata

def save_metadata_as_json(metadata, save_path):
    filename = os.path.join(save_path, "combined.json")
    with open(filename, 'w') as file:
        json.dump(metadata, file, indent=4)
    print(f"Metadata saved as {filename}")

验证代码

if __name__ == "__main__":
    combined = combine_metadata(acquisition_metadata, dataset_metadata, image_metadata)
    print(json.dumps(combined, indent=4))
    save_metadata_as_json(combined, "./")

运行后输出将完全符合期望的嵌套结构,无冗余键。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 07:57:04