2017-10-03 11 views
3

を使用するpython3.4 JSONとしてエクスポートされたファイアウォールルールベースをフィルタリングして辞書に変換しようとしています。私はユーザー定義の基準に基づいてフィルタを適用したいが、多くのループとif文を持つ構造を読みにくくすることができないように思えます。簡単で読みやすい方法でフィルタ辞書

私のファイアウォールのエントリのdictはかなり大きいので、私はそれらを短くしました。

2例:

entry1 = {'action': 'accept', 
      'dstintf': [{'name': 'ZN_HDW', 'q_origin_key': 'ZN_HDW'}], 
      'srcintf': [{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}] 
     } 
entry2 = {'action': 'accept', 
      'dstintf': [{'name': 'ZN_HDW', 'q_origin_key': 'ZN_HDW'}], 
      'srcintf': [{'name': 'ZN_DMZ', 'q_origin_key': 'ZN_DMZ'}, 
         {'name': 'ZN_MGMT', 'q_origin_key': 'ZN_MGMT'}, 
         {'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}] 
     } 

私は2例と比較するためのデータ構造を作成したいと次に作成した:私は終了し、これらの構造を比較する方法についていくつか検索した後

filter = {'action': 'accept', 
      'srcintf': [{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}] 
     } 

読みやすいコードで私の問題は、複数の送信元インターフェイスを持つentry2で評価されないということです。

>>> filter.items() <= entry1.items() 
True 
>>> filter.items() <= entry2.items() 
False 

どのようにすればいいですか?

EDIT: 以下の回答を使用して、私は何かを作成することができます(下記参照)。その他のヒント? 'dstintf''srcintf'内部

example = entry2 
# Compare entry to filter 
noMatch = 0 
for key in filter: 
    if isinstance(example[key], list): 
     # Convert list of dicts to list for easier comparing 
     tmpExample = [d['name'] for d in example[key]] 
     # Break if entry does not contain all criteria 
     if not all(value in tmpExample for value in filter[key]): 
      noMatch = 1 
      print("No match on: " + str(filter[key])) 
      break 
    elif filter[key] != example[key]: 
     # Simple string comparing 
     noMatch = 1 
     print("No match on: " + str(filter[key])) 
     break 

if noMatch == 0: 
    print("Match") 
else: 
    print(" No match") 

答えて

4

理論

データ構造は、この問題を容易にしません。 dictsのリストはほとんど決して正しいタイプではありません。

必要に応じて、あなたはおそらく辞書に変換する必要があります

>>> data = [{'name': 'ZN_DMZ', 'q_origin_key': 'ZN_DMZ'}, 
...      {'name': 'ZN_MGMT', 'q_origin_key': 'ZN_MGMT'}, 
...      {'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}] 
>>> {d['q_origin_key']:d['name'] for d in data} 
{'ZN_AUDIT': 'ZN_AUDIT', 'ZN_MGMT': 'ZN_MGMT', 'ZN_DMZ': 'ZN_DMZ'} 

しかしnameq_origin_key両方の値は常に同じであれば、あなただけのリストやセットを使用することができます。

>>> [d['name'] for d in data] 
['ZN_DMZ', 'ZN_MGMT', 'ZN_AUDIT'] 
>>> {d['name'] for d in data} 
set(['ZN_AUDIT', 'ZN_MGMT', 'ZN_DMZ']) 

ループやifを使わずにデータをフィルタリングする方が簡単です。

最後に、dict.items()は、タプルのリストを任意の順序で返します。

私はdict1.items() <= dict2.items()が何かを手伝ってくれるとは思いません。

複数の機能にコードを分割し、セットで動作するように良い考えかもしれません。これまでの助けを

query = {'action': 'accept', 
     'srcintf': [{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}] 
     } 

entry1 = {'action': 'accept', 
      'dstintf': [{'name': 'ZN_HDW', 'q_origin_key': 'ZN_HDW'}], 
      'srcintf': [{'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}] 
      } 

entry2 = {'action': 'accept', 
      'dstintf': [{'name': 'ZN_HDW', 'q_origin_key': 'ZN_HDW'}], 
      'srcintf': [{'name': 'ZN_DMZ', 'q_origin_key': 'ZN_DMZ'}, 
         {'name': 'ZN_MGMT', 'q_origin_key': 'ZN_MGMT'}, 
         {'name': 'ZN_AUDIT', 'q_origin_key': 'ZN_AUDIT'}] 
      } 


def compare_values(value1, value2): 
    if isinstance(value1, list) and isinstance(value2, list): 
     return set(d['name'] for d in value1).issubset(set(d['name'] for d in value2)) 
    else: 
     return value1 == value2 

def is_a_match(query, entry): 
    do_not_match = [key for key in query if not compare_values(
     query[key], entry.get(key))] 
    for key in do_not_match: 
     print("%r does not match" % key) 
    return len(do_not_match) == 0 

print(is_a_match(query, entry1)) 
# True 
print(is_a_match(query, entry2)) 
# True 
print(is_a_match({'action': 'decline'}, entry2)) 
# 'action' does not match 
# False 
+0

おかげで私の結果はまだ見(非常に読みやすいではありません編集)。その他のヒント? – marvink

+0

@marvink:更新を参照してください。今はもっと読みやすいかもしれません。 –

関連する問題