2017-09-19 77 views
8

我正在使用它返回的數據中非常詳細的API的幾個端點。我想將這些數據的一個子集提供給另一段代碼。如何屏蔽Python 3嵌套字典以返回僅包含特定項目的新字典?

假如我是給幾本詞典這樣的(這我通過計劃循環和過濾):

asset = { 
    'id': 1, 
    'name': 'MY-PC', 
    'owner': 'me', 
    'location': 'New York City', 
    'model': { 
     'id': 1, 
     'name': 'Surface', 
     'manufacturer': { 
      'id': 1, 
      'name': 'Microsoft' 
     } 
    } 
} 

我希望創建一個將在該字典的功能,具有「屏蔽」沿將被用於創建僅允許項目的新字典。

mask = { 
    'id': True, 
    'name': True, 
    'model': { 
     'id': True, 
     'name': True, 
     'manufacturer': { 
      'name': True 
     } 
    } 
} 

函數應該然後返回此:

mask = { 
    'id': 1, 
    'name': 'MY-PC', 
    'model': { 
     'id': 1, 
     'name': 'Surface', 
     'manufacturer': { 
      'name': 'Microsoft' 
     } 
    } 
} 

有已建成的東西,這可能是一個例子面罩(不過,我可以用任何格式,使生成的代碼最簡潔的工作)到Python 3,這將有助於這方面的援助?看起來如果我必須手動執行此操作,它會很快變得非常難看。我發現itertools.compress,但這似乎是列表,並不會處理字典的複雜性。

+0

您是否聽說過['jq(1)'](https://stedolan.github.io/jq/)? – o11c

+0

掩碼鍵沒有匹配的數據鍵時會發生什麼? –

回答

3

您可以遞歸通過只選擇相應的主值,建立從面罩新字典字典:

def prune_dict(dct, mask): 
    result = {} 
    for k, v in mask.items(): 
     if isinstance(v, dict): 
      value = prune_dict(dct[k], v) 
      if value: # check that dict is non-empty 
       result[k] = value 
     elif v: 
      result[k] = dct[k] 
    return result 

print(prune_dict(asset, mask)) 

{'id': 1, 
'model': {'id': 1, 'manufacturer': {'name': 'Microsoft'}, 'name': 'Surface'}, 
'name': 'MY-PC'} 
2

這是使用遞歸一個很好的機會,下面是一些示例代碼,我沒有測試過:

def copy(asset, result, mask): 
    for key_name, value in mask.items(): 
     if value == True: 
      result[key_name] = asset[key_name] 
     else: 
      result[key_name] = x = {} 
      copy(asset[key_name], x, value) 

y = {} 
copy(asset, y, mask) 
0

這可能會是一個遞歸函數。此外,對於面膜,我建議這種格式:mask = ["id", "name", "model.id", "model.name", "model.manufacturer.name"]

然後,你先留着,只有名爲掩碼中的條目:

def filterstage1(dictionary, mask): 
    result = {} 
    for key in dictionary: 
     if isinstance(dictionary[key], dict): 
      newmask = [maskname[mask.find(".") + 1:] for maskname in mask if maskname.startswith(key + ".")] 
      result[k] = filterstage1(dictionary[key], newmask) 
     elif key in mask: 
      result[key] = dictionary[key] 
    return result 

然後,根據您是否要刪除這是不是在面具,也沒有子元素子詞典,可以包括第二階段:

def filterstage2(dictionary, mask): 
    result = {} 
    for key in dictionary: 
     if not (isinstance(dictionary[key], dict) and dictionary[key] == {} and key not in mask): 
      result[key] = dictionary[key] 

最終代碼:filterstage2(filterstage1(dictionary, mask), mask)。如果您願意,您可以將兩個階段結合在一起。

+0

P.S.查看其他答案;這個解決方案對於生產代碼可能不是很好:P – HyperNeutrino