Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何将dict.get()与多维dict一起使用?_Python_Dictionary - Fatal编程技术网

Python 如何将dict.get()与多维dict一起使用?

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') 现在我只是检查顶

我有一个多维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')

现在我只是检查顶级键是否存在,然后将子值分配给变量(如果存在),或者
'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')