-1

给出以下列表:

mapping_list = ['location/name', 'location/address/address1', 'location/address/zip', 'location/business/business_name', 'occupant/occupant_type']

如何将其转换为嵌套字典,如下所示,其中最后一个值是最后一个键,默认值为空字符串。

{
    "location":
    {
        "name": "",
        "address":
        {
            "address1": "",
            "zip": ""
        },
        "business":
        {
            "business_name": ""
        }
    },
    "occupant":
    {
        "occupant_type": ""
    }
}

注意:给定的列表可以这样写:

mapping_list_of_lists = []

for full_path in mapping_list:
  path_list = full_path.split('/')
  mapping_list_of_lists.append(path_list)

print(mapping_list_of_lists)


[['location', 'name'], ['location', 'address', 'address1'], ['location', 'address', 'zip'], ['location', 'business', 'business_name'], ['occupant', 'occupant_type']]
4

2 回答 2

1

我确信有更好的方法,但你可以编写一个递归函数,dict用你所拥有的映射填充给定的值。

mapping_list = [
    'location/name', 
    'location/address/address1', 
    'location/address/zip', 
    'location/business/business_name', 
    'occupant/occupant_type'
]

def populate(mapping, dct, default=''):
    # check if '/' is in your current mapping
    if '/' in mapping:
        pos = mapping.find('/')
        part = mapping[:pos]
        # if it is and the next dict level does not exist yet
        # create the empty dict and recursively call the 
        # function to populate the inner parts with the
        # remainder of the mapping
        if part not in dct:
            dct[part] = dict()
        populate(mapping[pos+1:], dct[part], default=default)
    # otherwise, you're on your last part
    # and can safely fill the default value
    else:
        dct[mapping] = default

dct = {}
for mapping in mapping_list:
    populate(mapping, dct)
print(dct)

替代方法利用str.split('/')

mapping_list = [
    'location/name', 
    'location/address/address1', 
    'location/address/zip', 
    'location/business/business_name', 
    'occupant/occupant_type'
]

def populate(mapping, dct, default=''):
    if len(mapping) > 1:
        if mapping[0] not in dct:
            dct[mapping[0]] = dict()
        populate(mapping[1:], dct[mapping[0]], default=default)
    else:
        dct[mapping[0]] = default

mapping_list_of_lists = [i.split('/') for i in mapping_list]
dct = {}
for part in mapping_list_of_lists:
    populate(part, dct)
print(dct)
于 2021-09-13T14:58:20.253 回答
1

我认为这setdefault()对解决这个问题大有帮助,尽管您也可以使用嵌套的collections.defaultdict(). 我认为唯一的问题是在最后的叶子中你想要一个空字符串而不是空字典,否则它会很简单。

mapping_list = [
    'location/name', 
    'location/address/address1', 
    'location/address/zip', 
    'location/business/business_name', 
    'occupant/occupant_type'
]

result = {}

for keys in [keys.split("/") for keys in mapping_list]:
    tmp = result
    for index, key in enumerate(keys):
        default = "" if index == (len(keys) -1) else {}
        tmp = tmp.setdefault(key, default)

print(result)

这会给你:

{'location': {'name': '', 'address': {'address1': '', 'zip': ''}, 'business': {'business_name': ''}}, 'occupant': {'occupant_type': ''}}
于 2021-09-13T15:18:18.787 回答