2017-09-19 14 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

マスクキーに一致するデータキーがないとywhatが発生するはずですか? –

答えて

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

これはおそらく、再帰関数になります。また、マスクのために、私はこのフォーマットをお勧めします:削除したいかどうかに応じて、次に

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 

:次にmask = ["id", "name", "model.id", "model.name", "model.manufacturer.name"]

を、あなたは最初のマスクで命名されているエントリのみを保持したいです

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)マスクではありませんでしたし、何のサブ要素を持っていないサブディクショナリには、あなたは第二段階を含めることができます。必要に応じて、2つのステージを組み合わせることができます。

+0

P.S.他の答えを見てください。このソリューションは、おそらく生産コードではあまり良くありません:P – HyperNeutrino

関連する問題