简体   繁体   中英

Evaluate boolean logic using DFS in python dict

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM