将字符串转换为多级字典键?

3

我将为用户提供检查多层字典中特定键的能力。我的想法是他们会像这样传递键的路径:

root.subelement1.subelement2.key

这可以是任意长度和深度的字符串。

一旦我从用户那里得到了上面的字符串,我将把它分割并获得每个单独组件的列表:

elements = ['root', 'subelement1', 'subelement2', 'key']

我可以做到这一点。下一步是我卡住的地方。当它的长度任意时,我如何查询由上述指定的字典键?
我的初始想法是做类似于my_dict[elements[0]][elements[1]]的事情...但是当用户没有传递我期望的长度时,这种方法无法扩展或工作。
在这种情况下,我如何获取任意键深度的数据?
一些例子:
- 用户传递country.US.NewYork => 我查询 `my_dict['country']['US']['NewYork']` - 用户传递department.accounting => 我查询 my_dict['department']['accounting'] - 用户传递id => 我查询 my_dict['id'] - 用户传递district.District15.HenryBristow.principal => 我查询 my_dict['district']['District15']['HenryBristow']['principal']

我认为你需要创建一个循环:current = my_dict; for bit in query.split('.'): current = current[bit],当然还要加上缺失检查。 - Paul Panzer
5个回答

6

您可以使用reduce函数来查询嵌套字典中的键:

q = "district.District15.HenryBristow.principal"
my_dict  = {"district" : {"District15" : {"HenryBristow" : {"principal" : 12}}}}

from functools import reduce  # python 3 only

print(reduce(lambda x,y : x[y],q.split("."),my_dict))

结果:

12

如果你想避免在数据不存在的情况下捕获 KeyError,你可以使用带有空字典默认值的get

reduce(lambda x,y : x.get(y,{}),q.split("."),my_dict)

尝试获取一个未知的值将返回一个空字典。唯一的缺点是你不知道路径在哪里丢失了,所以也许让 KeyError 抛出并不会太糟糕:

try:
    v = reduce(lambda x,y : x[y],q.split("."),my_dict)
except KeyError as e:
    print("Missing key: {} in path {}".format(e,q))
    v = None

1
最后一个关于reduce的例子终于有很多意义了。 - VPfB
哇!非常感谢你。 - Smelly Cat

2
使用递归。例如:
root = {
    'subelement1': {
        'subelement2': {
            'key': 'value'
        }
    }
}

elements = ['subelement1', 'subelement2', 'key']


def getElem(d, keys):
    if keys == []:
        return None
    else:
        key = keys[0]
        remainingKeys = keys[1:]
        if remainingKeys == []:
            return d[key]
        else:
            if type(d[key]) == dict:
                return getElem(d[key], remainingKeys)
            else:
                return None


print(getElem(root, elements))

0

从 Python 2.x 的角度来看,您可以使用 reduce 来实现此操作。

query_list = keys.split(":")
print reduce(lambda x,y: x[y], [my_dict] + query_list)

但是一般来说,如果你想要进行错误处理而不仅仅是抛出一个 KeyError,你会希望使用递归或迭代函数来完成这个任务。


0

你可以像下面这样做

my_dict = someDict

tmpDict = dict(someDict)   # a coppy of dict
input = "x.u.z"
array = input.split(".")
for key in array:
    tmpDict = tmpDict[key]
print(tmpDict)

但是你的问题非常具有挑战性: 如果用户发送 country.us,则转到 my-dict.country.us

但是如果 my_dict 中的其中一个路径是列表,那么代码将会出错。 您可以通过检查类型来处理此问题。

if isinstance(tmpDict , dict ):
    tmpDict = tmpDict[key]
else:
    # u should say what u want else (a Recursive method u will need)

编辑 如果用户地址可能错误,您应该检查my_dict是否有此字段。示例代码如下,但如果我不喜欢这个,将会有很多! 如果键不在tmpDict中: print("错误路径") 返回


0
你可以使用for循环遍历字典:
s = 'root.subelement1.subelement2.key'
d1 = {'root':{'subelement1':{'subelement2':{'key':15, 'key1':18}}}}
new_d = d1
for key in s.split('.'):
    new_d = new_d[key]

print(new_d)

输出:

15

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接