【问题标题】:Getting a dictionary value where part of the key is in a string获取部分键在字符串中的字典值
【发布时间】:2016-08-20 20:42:30
【问题描述】:

拿一本字典

dict = {"word":{"a":{"b":2}}}

我想得到值 2。 要访问它,我可以这样做dict["word"]["a"]["b"]

但是我想知道我能否在字符串中包含部分键(["a"]["b] 部分)

然后像这样引用它

string = "[\"a\"][\"b\"]"

dict["word"]string

或者类似的东西

我知道这种语法是不正确的,但可以这样做吗?

在 Python 3.x 中

编辑: 一个更好的 dict 示例可能是这样的

    dict = {
"word":{"a":{"b":2}}
"hello":{"a":{"b":1}}
"mouse":{"a":{"b":5}}
}

在每种情况下如何获取 b 的值?您希望避免在密钥的 ["a"]["b"] 位中进行硬编码,以防万一发生更改。

【问题讨论】:

  • 使用这个的上下文是什么?
  • 这可能是“xy 问题”的情况 - 以这种方式通过字符串引用嵌套的字典项是不可能的,但你想要做的可能是……以另一种方式.那么,你想用它做什么呢?
  • Python 有一个 eval 函数,它可能会使其工作 - 但我同意以前的 cmets。
  • 否则你可以使用这样的想法:pypi.python.org/pypi/easydict
  • 我不明白为什么需要你使用这种方法?为什么不能只使用 .keys() 方法获取密钥?

标签: python string python-3.x dictionary


【解决方案1】:

不要使用dict 作为变量名,因为它会影响内置函数。


其中一种方法是使用re module。这里的主要思想是您使用正则表达式来找出键。获得键列表后,提取数据就很容易了。

>>> d = {"word":{"a":{"b":2}}}
>>> s = '["a"]["b"]'
>>> import re
>>> keys = re.findall(r'\["(.+?)"\]',s)
>>> d["word"][keys[0]][keys[1]]
2

如果有很多键,那么您可以使用来自functools 包的reduce。 (正如 JonClements 在comment 中提到的那样)

>>> import functools
>>> functools.reduce(dict.__getitem__, keys, d['word'])
2

对于更长的字典,您可以使用list comprehension

>>> d = {
... "word":{"a":{"b":2}},
... "hello":{"a":{"b":1}},
... "mouse":{"a":{"b":5}}
... }
>>> [functools.reduce(dict.__getitem__, keys, d[i]) for i in d]
[2, 5, 1]

但是请注意,由于字典键的无序性质,列表的输出可能与预期不同。一种更好的方法是将完整的字典简化为一个新的字典(使用字典理解),如

>>> {i:functools.reduce(dict.__getitem__, keys, d[i]) for i in d}
{'word': 2, 'mouse': 5, 'hello': 1}

【讨论】:

  • 当然——一旦你提取了密钥(无论使用何种语法),你就可以调整:functools.reduce(dict.__getitem__, 'ab', d['word']) 以使其更灵活...只需以良好的语法获取 'ab' (甚至可能从input 获取一些东西并在上面运行ast.literal_eval...)
  • 可能想让键成为一个列表/元组,而不是(即:保留你原来的re.findallkeys)的字符串,以防有多字符/非字符串键:)跨度>
  • 当然 - 当使用 list-comp 时,值的顺序(假设)它们很重要 - 除非来源是 OrderedDict :)
  • @Jon,是的。真的。也许我们可以有一个元组列表,如(键,值),像[('word', 2), ('mouse', 5), ('hello', 1)]
  • 或者只是一个新的dict{'word': 2, 'mouse': 5, 'hello': 1} - 但我们仍在猜测 OP 的用途......
【解决方案2】:

最好的方法是编写自己要解析的语法。你必须使用一个永远不会出现在键中的字符,一个流行的例子是.,但类似地,$| 也可以。

def get(d, key):
    kp = key.split('.')
    for k in kp:
        d = d[k]
    return d

d = {'a': {'b': 2}}
get(d, 'a.b')
>>> 2

编辑问题的更新:

那么您是否希望能够在每种情况下获得 a.b 的值列表?如果是这样你仍然可以像这样使用上面的方法

d = {
 "word":{"a":{"b":2}},
 "hello":{"a":{"b":1}},
 "mouse":{"a":{"b":5}},
}

# nesting calls to get just to show it is flexible like that
[get(get(d, k), 'a.b') for k in d.keys()]
# if you wanted to generate a dict of {"word": val} it would look like this
{k:get(get(d, k), 'a.b') for k in d.keys()}

如果你的可变部分在中间,它甚至可以工作

d = {
 "x": {"word":{"a":{"b":2}}},
 "x": {"hello":{"a":{"b":1}}},
 "x": {"mouse":{"a":{"b":5}}},
}

# using more calls to get just to show it is flexible like that
[get(get(d, 'x.'+k), 'a.b') for k in get(d, 'x').keys()]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-01
    • 2013-07-02
    • 2021-06-16
    • 2016-12-16
    • 2016-06-24
    • 2012-05-09
    • 1970-01-01
    • 2015-02-02
    相关资源
    最近更新 更多