如何创建项目并将其添加到嵌套词典中?

How do you create and add items to a nested dictionary?

提问人:boondockorphan 提问时间:10/7/2023 最后编辑:John Gordonboondockorphan 更新时间:10/7/2023 访问量:104

问:

我想遍历一个列表,首先检查字典中是否存在一个项目,如果存在,我想跳过它并继续前进,如果没有,我想将其添加到字典中的相应级别。

我从空字典和这个列表列表开始

my_dictionary = {}

file1 = ['model_a', 'part_a', 'category_a', 'format_a', 'version_a', 'filename_a']
file2 = ['model_b', 'part_a', 'category_a', 'format_a', 'version_a', 'filename_a']
file3 = ['model_a', 'part_b', 'category_a', 'format_a', 'version_a', 'filename_b']
file4 = ['model_c', 'part_a', 'category_a', 'format_a', 'version_a', 'filename_a']
file5 = ['model_b', 'part_a', 'category_a', 'format_b', 'version_a', 'filename_a']
file6 = ['model_a', 'part_a', 'category_a', 'format_a', 'version_b', 'filename_a']

file_list = [file1, file2, file3, file4, file5, file6]

我创建了一个循环并创建变量来检查并写入字典:

for item in file_list:
    model, pn, category, file_format, version, filename = item

我的目标是:

    {
         "model_a": {
             "part_a": {
                 "category_a": {
                     "format_a": {
                         "version_a": "filename_a",
                         "version_b": "filename_a"
                     }
                 }
             },
             "part_b": {
                 "category_a": {
                     "format_a": {
                         "version_a": "filename_b"
                     }
                 }
             }
         },
         "model_b": {
             "part_a": {
                 "category_a": {
                     "format_a": {
                         "version_a": "filename_a"
                     },
                     "format_b": {
                         "version_a": "filename_a"
                     }
                 }
             }
         },
         "model_c": {
             "part_a": {
                 "category_a": {
                     "format_a": {
                         "version_a": "filename_a"
                     }
                 }
             }
         }
     }

所需结果的树状图像

第一次尝试只是在每个循环中写入项目,而不先检查:

# first attempt
for item in file_list:
    model, pn, category, file_format, version, filename = item

    my_object = {pn: {category: {file_format: {version: filename}}}}
    my_dictionary[model] = my_object

这使得它通过循环,但覆盖项目而不是添加缺失的部分。

接下来的尝试是使用 try/except 并逐步遍历字典的每个级别来检查键。它在第一级工作,并生成缺少的密钥,并跳过现有密钥。

    try:
        my_dictionary[model]
    except (KeyError, IndexError):
        model_exists = False
    else:
        model_exists = True

    if not model_exists:
        my_dictionary[model] = {pn}

在此步骤中,我成功创建了一个值为 key = pn 的 key = 模型,但是当我在下一个级别尝试相同的方法时:

    try:
        my_dictionary[model][pn]

我得到:“TypeError:'set'对象不可下标。我正在运行 3.10.1,我在那里订购了字典。

我觉得这可能是一个解决方案:从嵌套列表创建一个嵌套词典,因为发布的问题看起来像我想做的事情,但老实说,这对我来说毫无意义。

Python 字典 嵌套

评论

0赞 Ignatius Reilly 10/7/2023
{pn}创建一个集合,而不是一个字典。
0赞 Barmar 10/7/2023
您链接到的问题就是解决方案,您只需要对列表中的每个项目重复它。如果它在那里没有意义,那么如果我们在这里重复它,它就没有任何意义了。
0赞 John Gordon 10/7/2023
但老实说,这对我来说毫无意义你能解释一下,到底什么是没有意义的吗?
0赞 boondockorphan 10/7/2023
@JohnGordon 我对 python 和编程非常陌生。“这没有意义”是我还没有遇到过“集合”或“defaultdict”或“lambda”。我会研究这些项目。当我第一次看到那篇帖子时,它似乎远远超出了我现在的知识范围,我希望有一个不那么优雅、更适合初学者的解决方案。也许当我开始阅读这些项目时,我将能够稍微理解它们。

答:

1赞 JonSG 10/7/2023 #1

在这里,是你的朋友。dictionary 方法将帮助我们初始化给定键所需的子字典。如果你用过,那么你已经有了基本的了解。当然,这里也可以使用嵌套。我更喜欢它,因为它最终给你留下了一本普通的旧词典。setdefault()setdefault()collections.defaultdict()defaultdict()setdefault()defaultdict()

请注意,我奇怪地格式化了这一行,以便更容易阅读。

import json

file1 = ['model_a', 'part_a', 'category_a', 'format_a', 'version_a', 'filename_a']
file2 = ['model_b', 'part_a', 'category_a', 'format_a', 'version_a', 'filename_a']
file3 = ['model_a', 'part_b', 'category_a', 'format_a', 'version_a', 'filename_b']
file4 = ['model_c', 'part_a', 'category_a', 'format_a', 'version_a', 'filename_a']
file5 = ['model_b', 'part_a', 'category_a', 'format_b', 'version_a', 'filename_a']
file6 = ['model_a', 'part_a', 'category_a', 'format_a', 'version_b', 'filename_a']
file_list = [file1, file2, file3, file4, file5, file6]
my_dictionary = {}
for model, pn, category, file_format, version, filename in file_list:
    my_dictionary \
        .setdefault(model, {}) \
        .setdefault(pn, {}) \
        .setdefault(category, {}) \
        .setdefault(file_format, {})[version] = filename
print(json.dumps(my_dictionary, indent=4))

这也可能有助于说明正在发生的事情。

my_dictionary = {}
for model, pn, category, file_format, version, filename in file_list:
    target = my_dictionary.setdefault(model, {})
    target = target.setdefault(pn, {})
    target = target.setdefault(category, {})
    target = target.setdefault(file_format, {})
    target[version] = filename

无论哪种格式,您都可以:

{
    "model_a": {
        "part_a": {
            "category_a": {
                "format_a": {
                    "version_a": "filename_a",
                    "version_b": "filename_a"
                }
            }
        },
        "part_b": {
            "category_a": {
                "format_a": {
                    "version_a": "filename_b"
                }
            }
        }
    },
    "model_b": {
        "part_a": {
            "category_a": {
                "format_a": {
                    "version_a": "filename_a"
                },
                "format_b": {
                    "version_a": "filename_a"
                }
            }
        }
    },
    "model_c": {
        "part_a": {
            "category_a": {
                "format_a": {
                    "version_a": "filename_a"
                }
            }
        }
    }
}

评论

1赞 boondockorphan 10/7/2023
谢谢!我尝试了您提供的东西,它奏效了,这非常好。我正在阅读有关setdefault的信息,以了解它为什么有效。我读了几篇文章,我需要练习使用它。对我最有帮助的是你对目标的说明=......目标 =。对我来说,这是一个完美的例证,说明在循环列表时如何使用 setdefault() 分配变量。再次感谢大家。
0赞 treuss 10/7/2023 #2

看起来像是递归的一个很好的用例:

def update_dict(dictionary, items):
    if len(items) == 2:
        dictionary[items[0]] = items[1]
    else:
        if items[0] not in dictionary:
            dictionary[items[0]] = {}
        update_dict(dictionary[items[0]], items[1:])

my_dictionary = {}

file1 = ['model_a', 'part_a', 'category_a', 'format_a', 'version_a', 'filename_a']
file2 = ['model_b', 'part_a', 'category_a', 'format_a', 'version_a', 'filename_a']
file3 = ['model_a', 'part_b', 'category_a', 'format_a', 'version_a', 'filename_b']
file4 = ['model_c', 'part_a', 'category_a', 'format_a', 'version_a', 'filename_a']
file5 = ['model_b', 'part_a', 'category_a', 'format_b', 'version_a', 'filename_a']
file6 = ['model_a', 'part_a', 'category_a', 'format_a', 'version_b', 'filename_a']

file_list = [file1, file2, file3, file4, file5, file6]

for file in file_list:
    update_dict(my_dictionary, file)

递归函数也可以写得更短,使用:setdefault

def update_dict(dictionary, items):
    if len(items) == 2:
        dictionary[items[0]] = items[1]
    else:
        update_dict(dictionary.setdefault(items[0], {}), items[1:])