26

我有一个多维字典,我希望能够通过键:键对检索一个值,如果第一个键不存在,则返回“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 次,并且还从其他地方检索/生成有关每个顶级密钥的其他信息,并且我正在尝试加快速度。

4

4 回答 4

35

怎么样

d.get('a', {'j': 'NA'})['j']

?

如果不是所有的 subdicts 都有一个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}
            })
于 2013-04-14T19:36:29.297 回答
5

这是使用普通字典执行此操作的一种简单有效的方法,嵌套任意数量的级别。示例代码适用于 Python 2 和 3。

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,))

虽然这样做的方式不如第一种有效。

于 2013-04-14T19:56:55.417 回答
5

获取多维dict示例的另一种方法(两次使用get方法)

d.get('a', {}).get('j')
于 2017-07-20T05:02:03.637 回答
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'
于 2013-04-14T19:52:24.427 回答