2013-04-14 83 views
11

我有一個多維的字典,我想能夠檢索由密鑰值:密鑰對,並返回「NA」如果第一個鍵不存在。所有的子字典都有相同的密鑰。Python的dict.get()多維字典

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次的工作,並且還從別處檢索/生成關於每個頂級密鑰的其他信息,並且我試圖加快這一點。

回答

20

如何

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} 
      }) 
+0

看看'collections.defaultdict'對於一個已經提供的實現,即'defaultdict(拉姆達:defaultdict(拉姆達: 'NA') )' – mtadd

+0

當然,但你仍然需要一個'NADict'和一個返回它的共享實例的函數。我會添加一個例子。 –

+0

@mtadd:這個想法是不會在每次誤查時創建一個新的dict/defaultdict。 –

2

不是嵌套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' 
4

下面是一個簡單而有效的方式與普通的字典做,嵌套層次任意數量的:

d = {'a': {'j': 1, 'k': 2}, 
    'b': {'j': 2, 'k': 3}, 
    'd': {'j': 1, 'k': 3}, 
    } 

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) 

print chained_get(d, 'a', 'j') # 1 
print chained_get(d, 'b', 'k') # 3 
print chained_get(d, 'k', 'j') # NA 

它也可能是遞歸地完成:

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

儘管這樣做並不像前者那樣高效。

0

另一種方式來獲得多維字典爲例(使用GET方法兩次)

d.get('a', {}).get('j')