I have a dict structure that appears like the following:
{
"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
}
]
}
For each rule, I derive a decision and attach it to the policy rule. I do that via a simple recursive walk of the dict. In the above sample policy, the boolean logic equates to the following:
(True and True and (False or True or False) and False)
I'd like to have a function that takes this policy in and is able to derive the boolean logic in order to return the final evaluation. I know a depth-search first approach is liable to be the direction here, but am struggling with how to maintain the boolean state and know which level I am at within the structure.
Create a dictionary to hold functions that correspond to 'conditions'
import operator, functools
operations = {'AND':operator.and_, 'OR':operator.or_, 'XOR':operator.xor}
Write a recursive function that will recurse when 'conditions'
is a key in a rule, otherwise iterate over the rules and accumulate 'decisions'
in a list. Use functools.reduce
to apply the condition
to the decisions.
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
was meant to be the base case but I'm not so sure it's needed - if that happens the dict is messed up and it probably should raise a ValueError
I think this has an implicit base case (if there is such a thing) - it relies on the for rule in d['rules']:
loop to run out of items.
If the conditions limited to 'AND' and 'OR' you can use all
and 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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.