我有一个字典结构,如下所示:
{
"condition": "AND",
"rules": [
{
"id": "monitor_category",
"field": "monitor_category",
"type": "string",
"input": "select",
"operator": "equal",
"value": "Competition",
"decision": True
},
{
"id": "monitor_tag",
"field": "monitor_tag",
"type": "string",
"input": "text",
"operator": "equal",
"value": "PassiveTotal",
"decision": True
},
{
"condition": "OR",
"rules": [
{
"id": "article_tag",
"field": "article_tag",
"type": "string",
"input": "text",
"operator": "contains",
"value": "Attack",
"decision": False
},
{
"id": "article_tag",
"field": "article_tag",
"type": "string",
"input": "text",
"operator": "contains",
"value": "Hunt",
"decision": True
},
{
"id": "article_tag",
"field": "article_tag",
"type": "string",
"input": "text",
"operator": "contains",
"value": "Threat",
"decision": False
}
]
},
{
"id": "monitor_tag",
"field": "monitor_tag",
"type": "string",
"input": "text",
"operator": "equal",
"value": "Analysis",
"decision": False
}
]
}
对于每个规则,我都会派生一个决策并将其附加到策略规则。我通过字典的简单递归行走来做到这一点。在上面的示例策略中,布尔逻辑等同于以下内容:
(True and True and (False or True or False) and False)
我想要一个函数来接受这个策略,并能够派生布尔逻辑以返回最终评估。我知道深度搜索优先的方法可能是这里的方向,但我正在努力保持布尔状态并知道我在结构中处于哪个级别。
创建一个字典来保存与'conditions'
对应的函数
import operator, functools
operations = {'AND':operator.and_, 'OR':operator.or_, 'XOR':operator.xor}
编写一个递归函数,当'conditions'
是规则中的键时,该函数将递归,否则迭代规则并在列表中累积'decisions'
。 使用functools.reduce
将condition
应用于决策。
def f(d):
func = operations.get(d['condition'], None)
if func is None:
return
decisions = []
for rule in d['rules']:
if 'condition' in rule:
decision = f(rule)
else:
decision = rule['decision']
decisions.append(decision)
return functools.reduce(func, decisions)
if func is None: return
应该是基本情况,但我不确定是否需要它 - 如果发生这种情况,字典就搞砸了,它可能应该引起ValueError
我认为这有一个隐含的基本情况(如果有这样的事情( - 它依赖于for rule in d['rules']:
循环来耗尽项目。
如果条件限制为"AND"和"OR",则可以使用all
和any
。
ops = {'AND':all, 'OR':any}
def g(d):
func = ops.get(d['condition'], None)
if func is None:
return
decisions = []
for rule in d['rules']:
if 'condition' in rule:
decision = f(rule)
else:
decision = rule['decision']
decisions.append(decision)
return func(decisions)