0
votes

This is my first post here, and I hope that my question is clear and formatted correctly...

I have two dictionaries. The first dictionary contains what I'm calling "Option Expressions" as keys and arbitrary items for values:

dict1 = {'((opt1 OR opt4 OR opt6) AND NOT opt7)': 'Yellow Roof', '((opt2 AND opt3) XOR opt5': 'Purple Scooter'}

print(dict1)

{'((opt1 OR opt4 OR opt6) AND NOT opt7)': 'Yellow Roof',
'((opt2 AND opt3) XOR opt5': 'Purple Scooter'}

The second dictionary contains the options from dict1 as keys and whether or not they were "Accepted" or "Rejected" as values:

dict2 = {'opt1': 'Accepted', 'opt2': 'Rejected', 'opt3': 'Rejected','opt4': 'Accepted', 'opt5': 'Accepted', 'opt6': 'Rejected','opt7': 'Accepted'}

print(dict2)

{'opt1': 'Accepted',
 'opt2': 'Rejected',
 'opt3': 'Rejected',
 'opt4': 'Accepted',
 'opt5': 'Accepted',
 'opt6': 'Rejected',
 'opt7': 'Accepted'}

How would I go about evaluating the expressions from dict1 as True or False to determine which items were selected based on whether opt's from dict2 were accepted or rejected?

My initial thought was to replace the opt's in the expressions with 1 for accepted and 0 for rejected to have something like:

((1 OR 1 OR 0) AND NOT 1) Which would evaluate as False

and

((0 AND 0) XOR 1) Which would evaluate as True

I've been doing some research into pyparsing and think it would be useful here, though I am not entirely sure how best to utilize it.

I am applying boolean logic:

AND: True if and only if both sides are true

OR: True if either side is true

NOT/(AND NOT): Changes true to false and false to true

XOR: True if one side is true (but not both)

2
Are opt values bool-normalized or can they have a different value than Accepted or Rejected? - zwer
@zwer they are! They are only accepted or rejected. - Luxo_Jr
"I'm not sure how to use it" doesn't make a good question. Read the doc, it will tell you how to use it, or explain exactly what you have tried and why it doesn't work. - Julien
And btw, I suspect you inverted the keys and values in dict1... - Julien

2 Answers

1
votes

With little bit of massaging the data you can turn it into valid Python and let the Python interpreter do your bidding:

# Mandatory warning here about using eval() - here be dragons!

dict1 = {"((opt1 OR opt4 OR opt6) AND NOT opt7)": "Yellow Roof",
         "((opt2 AND opt3) XOR opt5)": "Purple Scooter"}

dict2 = {"opt1": "Accepted",
         "opt2": "Rejected",
         "opt3": "Rejected",
         "opt4": "Accepted",
         "opt5": "Accepted",
         "opt6": "Rejected",
         "opt7": "Accepted"}

# lets first normalize the 'opt' codes to True/False
dict2_norm = {k: (True if v == "Accepted" else False) for k, v in dict2.items()}

# Now all we need to do is evaluate the expressions:
for expression, value in dict1.items():
    # Let's first normalize the expression to Python-digestible
    expression = expression.replace("XOR", "is not").replace("OR", "or")\
        .replace("AND", "and").replace("NOT", "not")
    if eval(expression, dict2_norm):
        print(value)

# prints: Purple Scooter
0
votes

Here is a solution I came up with. It assumes you've already replaced the 'Accepted' and 'Rejected' with True and False (or 1 and 0 like you said in your question.)

This then will process the results. It first formats the results into valid Python code ('xor' -> ^, 'AND' -> and, and 'OR' -> or), replaces the opt values with their boolean counterparts, and finally evaluates the expression using the eval builtin.

input_code = '((opt1 OR opt4 OR opt6) AND NOT opt7)'
input_w_xor = '(opt2 AND opt3) XOR opt5'
result_codes = {'opt1': True, 'opt2': False, 'opt3': False,'opt4': True, 'opt5': True, 'opt6': False,'opt7': True}


def process_code(input_code, result_codes):
    input_code = input_code.lower()

    def replace_op_codes(code):
        for opt_key, opt_value in result_codes.items():
            code =  code.replace(opt_key, str(opt_value))
        return code

    input_code = replace_op_codes(input_code)
    input_code = input_code.replace("xor", '^')
    result = eval(input_code)

    return result


print(process_code(input_code, result_codes))
print(process_code(input_w_xor, result_codes))

I tend to shy away from using eval and exec, but I think it is the quickest solution in this case.