Python 如何将dict.get()与多维dict一起使用?
我有一个多维dict,我希望能够通过key:key对检索一个值,如果第一个键不存在,则返回'NA'。所有子目录都有相同的键Python 如何将dict.get()与多维dict一起使用?,python,dictionary,Python,Dictionary,我有一个多维dict,我希望能够通过key:key对检索一个值,如果第一个键不存在,则返回'NA'。所有子目录都有相同的键 d = { 'a': {'j':1,'k':2}, 'b': {'j':2,'k':3}, 'd': {'j':1,'k':3} } 我知道我可以使用d.get('c','NA')获取子目录,如果它存在,则返回'NA',但是我确实只需要子目录中的一个值。如果存在,我想做类似d.get('c['j'],'NA') 现在我只是检查顶
d = { 'a': {'j':1,'k':2},
'b': {'j':2,'k':3},
'd': {'j':1,'k':3}
}
我知道我可以使用d.get('c','NA')
获取子目录,如果它存在,则返回'NA',但是我确实只需要子目录中的一个值。如果存在,我想做类似d.get('c['j'],'NA')
现在我只是检查顶级键是否存在,然后将子值分配给变量(如果存在),或者'NA'
如果不存在。然而,我这样做了大约500k次,还从其他地方检索/生成了关于每个顶级密钥的其他信息,我正在尝试加快速度。怎么样
d.get('a', {'j': 'NA'})['j']
?
如果不是所有子部分都有j
键,则
d.get('a', {}).get('j', 'NA')
为了减少创建的相同对象,您可以设计如下
class DefaultNASubdict(dict):
class NADict(object):
def __getitem__(self, k):
return 'NA'
NA = NADict()
def __missing__(self, k):
return self.NA
nadict = DefaultNASubdict({
'a': {'j':1,'k':2},
'b': {'j':2,'k':3},
'd': {'j':1,'k':3}
})
print nadict['a']['j'] # 1
print nadict['b']['j'] # 2
print nadict['c']['j'] # NA
使用defaultdict
也有同样的想法:
import collections
class NADict(object):
def __getitem__(self, k):
return 'NA'
@staticmethod
def instance():
return NADict._instance
NADict._instance = NADict()
nadict = collections.defaultdict(NADict.instance, {
'a': {'j':1,'k':2},
'b': {'j':2,'k':3},
'd': {'j':1,'k':3}
})
与嵌套的
dict
对象的层次结构不同,您可以使用一个字典,其键是表示层次结构中路径的元组
In [34]: d2 = {(x,y):d[x][y] for x in d for y in d[x]}
In [35]: d2
Out[35]:
{('a', 'j'): 1,
('a', 'k'): 2,
('b', 'j'): 2,
('b', 'k'): 3,
('d', 'j'): 1,
('d', 'k'): 3}
In [36]: timeit [d[x][y] for x,y in d2.keys()]
100000 loops, best of 3: 2.37 us per loop
In [37]: timeit [d2[x] for x in d2.keys()]
100000 loops, best of 3: 2.03 us per loop
通过这种方式访问看起来要快15%。您仍然可以使用带有默认值的get
方法:
In [38]: d2.get(('c','j'),'NA')
Out[38]: 'NA'
这里有一个简单而有效的方法来处理普通字典,它嵌套了任意数量的级别。示例代码在Python2和Python3中都可以使用
from __future__ import print_function
try:
from functools import reduce
except ImportError: # Assume it's built-in (Python 2.x)
pass
def chained_get(dct, *keys):
SENTRY = object()
def getter(level, key):
return 'NA' if level is SENTRY else level.get(key, SENTRY)
return reduce(getter, keys, dct)
d = {'a': {'j': 1, 'k': 2},
'b': {'j': 2, 'k': 3},
'd': {'j': 1, 'k': 3},
}
print(chained_get(d, 'a', 'j')) # 1
print(chained_get(d, 'b', 'k')) # 3
print(chained_get(d, 'k', 'j')) # NA
也可以递归地进行:
# Recursive version.
def chained_get(dct, *keys):
SENTRY = object()
def getter(level, keys):
return (level if keys[0] is SENTRY else
'NA' if level is SENTRY else
getter(level.get(keys[0], SENTRY), keys[1:]))
return getter(dct, keys+(SENTRY,))
尽管这种方法不如第一种方法有效。获取多维dict示例的另一种方法(使用get方法两次)
查看
collections.defaultdict
以了解已提供的实现,即defaultdict(lambda:defaultdict(lambda:'NA'))
当然可以,但您仍然需要一个NADict
和一个返回其共享实例的函数。我将添加一个示例。@mtadd:我们的想法是不要在每次错误查找时创建新的dict/defaultdict。这是一个很好的解决方案。当我从内部字典中查找丢失的键时,仍然会出现一个KeyError
。e、 当然,它们只是口述。“所有的子目录都有相同的键”,OP说。我的50美分:一定要导入函数:来自functools import reduce
@Amfasis:这个答案是为Python2.x编写的,在该版本中是内置的。很公平,但通过这个简单的导入,它也在Python3上工作,Python3现在正成为主要版本(我知道你的答案是6年前的:-)@Amfasis:我相信他们将它添加到Python 2.7中的functools
,以使人们更容易过渡到Python 3。
d.get('a', {}).get('j')