简体   繁体   English

避免将关键值存储在嵌套字典中的错误(Python)

[英]Avoiding key error storing values in nested dictionary (Python)

Introduction 介绍

Following dictionary has three levels of keys and then a value. 接下来的字典具有三个级别的键,然后是一个值。

d = {
    1:{
        'A':{
            'i': 100,
            'ii': 200
            }, 
        'B':{
            'i': 300
            }
        }, 
    2:{
        'A':{
            'ii': 500
            }
        }
    }

Examples that need to be added. 需要添加示例。

d[1]['B']['ii'] = 600      # OK
d[2]['C']['iii'] = 700     # Keyerror on 'C'
d[3]['D']['iv'] = 800      # Keyerror on 3

Problem Statement 问题陈述

I wanted to create code that would create the necessary nested keys and avoid any key errors. 我想创建可以创建必要的嵌套键并避免任何键错误的代码。

Solution 1 解决方案1

The first solution I came up with, was: 我想到的第一个解决方案是:

def NewEntry_1(d, lv1, lv2, lv3, value):
    if lv1 in d:
        if lv2 in d:
            d[lv1][lv2][lv3] = value
        else:
            d[lv1][lv2] = {lv3: value}
    else:
        d[lv1] = {lv2: {lv3: value}}

Seems legit, but embedding this in order pieces of code made it mind boggling. 看起来合法,但是将其嵌入顺序的代码会使人感到困惑。 I explored Stackoverflow for other solutions and was reading on the get() and setdefault() functions. 我探索了Stackoverflow的其他解决方案,并正在阅读get()和setdefault()函数。

Solution 2 解决方案2

There is plenty of material to find about get() and setdefault(), but not so much on nested dictionaries. 有很多关于get()和setdefault()的资料,但是在嵌套字典上则没有那么多。 Ultimately I was able to come up with: 最终,我得以提出:

def NewEntry_2(d, lv1, lv2, lv3, value):
    return d.setdefault(lv1, {}).setdefault(lv2,{}).setdefault(lv3, value)

It is one line of code so it is not really necessary to make it a function. 它是一行代码,因此实际上没有必要使其成为函数。 Easily modifiable to include operations: 易于修改以包括以下操作:

d[lv1][lv2][lv3] = d.setdefault(lv1, {}).setdefault(lv2,{}).setdefault(lv3, 0) + value

Seems perfect? 看起来很完美?

Question

When adding large quantities of entries and doing many modifications, is option 2 better than option 1? 当添加大量条目并进行许多修改时,选项2是否优于选项1? Or should I define function 1 and call it? 还是应该定义函数1并调用它? The answers I'm looking should take into account speed and/or potential for errors. 我正在寻找的答案应考虑速度和/或潜在的错误。

Examples 例子

NewEntry_1(d, 1, 'B', 'ii', 600)
# output = {1: {'A': {'i': 100, 'ii': 200}, 'B': {'i': 300, 'ii': 600}}, 2: {'A': {'ii': 500}}}

NewEntry_1(d, 2, 'C', 'iii', 700)
# output = {1: {'A': {'i': 100, 'ii': 200}, 'B': {'i': 300, 'ii': 600}}, 2: {'A': {'ii': 500}, 'C': {'iii': 700}}}

NewEntry_1(d, 3, 'D', 'iv', 800)
# output = {1: {'A': {'i': 100, 'ii': 200}, 'B': {'i': 300, 'ii': 600}}, 2: {'A': {'ii': 500}, 'C': {'iii': 700}}, 3: {'D': {'iv': 800}}}

More background 更多背景

I'm a business analyst exploring using Python for creating Graph DB that would help me with very specific analysis. 我是一名业务分析师,正在探索使用Python创建Graph DB,这将有助于我进行非常具体的分析。 The dictionary structure is used to story the influence one node has on one of its neighbors: 字典结构用于说明一个节点对其邻居之一的影响:

  • lv1 is Node From lv1是节点来自
  • lv2 is Node To lv2是节点到
  • lv3 is Iteration lv3是迭代
  • value is Influence (in %) 值是影响力(以%为单位)

In the first iteration Node 1 has direct influence on Node 2. In the second iteration Node 1 influences all the Nodes that Node 2 is influencing. 在第一次迭代中,节点1直接影响节点2。在第二次迭代中,节点1影响节点2影响的所有节点。

I'm aware of packages that can help me with it (networkx), but I'm trying to understand Python/GraphDB before I want to start using them. 我知道可以帮助我解决问题的软件包(networkx),但是在尝试开始使用它们之前,我正在尝试了解Python / GraphDB。

As for the nested dictionaries, you should take a look at defaultdict . 至于嵌套字典,您应该看一下defaultdict Using it will save you a lot of the function-calling overhead. 使用它可以节省许多函数调用开销。 The nested defaultdict construction resorts to lambda functions for their default factories: 嵌套的defaultdict构造为其默认工厂defaultdict lambda函数:

d = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))  # new, shiny, empty
d[1]['B']['ii'] = 600      # OK
d[2]['C']['iii'] = 700     # OK
d[3]['D']['iv'] = 800      # OK

Update: A useful trick to know to create a deeply nested defaultdict is the following: 更新:以下是创建深层嵌套defaultdict有用技巧:

def tree():
    return defaultdict(tree)

d = tree()  
# now any depth is possible
# d[1][2][3][4][5][6][7][8] = 9

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM