问题
I'm trying to write a function that will take in two arguments (one list and one dictionary) and return the output for instance, like so:
>>>interpret(["door_open", "AND", "cat_gone"],
{"door_open" : "false", "cat_gone" : "true", "cat_asleep" : "true"})
'false'
or
interpret(["cat_asleep", "OR", ["NOT", "cat_gone"]],
{"door_open" : "false", "cat_gone" : "true", "cat_asleep" : "true"})
'true'
..............................................................................................................................................................
As I want to use as few logical statements as possible in this particular function, I have created a couple of separate functions that will do this instead:
def and_function(expression1, expression2):
if expression1=="true" and expression2=="true":
return "true"
else:
return "false"
def or_function(expression1, expression2):
if expression1== "true" or expression2=="true":
return "true"
else:
return "false"
def not_function(expression):
if expression == "true":
return "false"
elif expression == "false":
return "true"
..............................................................................................................................................................
However, now I have been stuck for sometime, as I don't quite understand how the program is suppose to first go through the list and nested lists. Then go through the dictionary pick out the value related to the key (which is in the list) and then put compare the values in the list to each other together with the logical statement. I get that recursion of some form is probably needed in order to go through the nested lists, but can't really figure out how to put it all together.
Any ideas on how to solve this kind of problem?
回答1:
improved version of answer here.
There is no exception handling done here, so I think code will work just fine if its guaranteed that list ( argument) passed has valid structure for example OR, AND operator if present in list should have operand on both the sides.
..........................................................................................................................................................
helper functions that you have written will be called through this dicts.
binary_bool_dict = {'AND':and_function, 'OR':or_function}
unary_bool_dict = {'NOT':not_function}
..........................................................................................................................................................
Using recursion we can solve this problem, whenever 1) we have not interpreted the item like when doing AND function call we are getting item from right hand side ie item which we have not visited yet( since we traverse from left to right ie from index 0 --> len(list)) or 2) item is a list we will make a recursive call.
function interpret will return 'true' or 'false'
def interpret( lst, dct):
if isinstance( lst, list):
temp_result = None
#print( lst)
for idx, item in enumerate( lst):
#print( idx,'item',item)
if item == 'true' or item == 'false':
continue
elif isinstance( item, list):
lst[idx] = interpret( item,dct)
elif item in dct:
lst[idx] = dct[item]
else:
lst[idx+1] = interpret( lst[ idx+1],dct)
if item in binary_bool_dict:
if temp_result == None:
temp_result = binary_bool_dict[item]( lst[ idx-1], lst[idx+1])
else:
temp_result = binary_bool_dict[item]( temp_result, lst[idx+1])
else:
# item in unary_bool_dict:
temp_result = unary_bool_dict[item](lst[idx+1])
return temp_result # eventually temp_result will become our final answer
else:
return dct.get( lst,lst) # if key: lst is present in dct get its value else just return lst ( it must be already a 'true' or 'false')
................................................................................................................................................................
print(interpret(["door_open", "AND", "cat_gone"],
{"door_open" : "false", "cat_gone" : "true", "cat_asleep" : "true"} )) #'false'
print(interpret(["cat_asleep", "OR", ["NOT", "cat_gone"]],
{"door_open" : "false", "cat_gone" : "true", "cat_asleep" : "true"})) #'true'
print(interpret(["true", "OR", "true"], {})) #'true'
print(interpret("cat_gone", {"door_open": "false", "cat_gone": "true"})) #'true'
print(interpret(["NOT", ["NOT", ["NOT", ["cat_asleep", "OR", ["NOT", "cat_asleep"]]]]],
{"cat_asleep": "false"})) #'false'
print(interpret(["NOT", "AND", "true"], {"NOT":"true"})) #'true'
print(interpret(["NOT", "AND"], {"AND": "false"})) #'true'
回答2:
You could split the operators out into their own functions, but I'm not sure how much clarity that adds when there are only three. I wrote the actual function to work with booleans, because I think it ends up a bit cleaner.
def interpret(conditions, states):
return "true" if _interpret(
conditions,
{k: v == "true" for k, v in states.items()},
) else "false"
def _interpret(conditions, states):
# NOT is a special case; just one argument in position 1
if conditions[0] == "NOT":
if type(conditions[1]) == list:
value = _interpret(conditions[1], states)
else:
value = states[conditions[1]]
return not value
if type(conditions[0]) == list:
first = _interpret(conditions[0], states)
else:
first = states[conditions[0]]
if type(conditions[2]) == list:
second = _interpret(conditions[2], states)
else:
second = states[conditions[2]]
return (first and second) if (conditions[1] == "AND") else (first or second)
Shortening that up a bit:
import operator
def _interpret(c, s):
if c[0] == "NOT":
return not (_interpret(c[1], s) if (type(c[1]) == list) else s[c[1]])
return (operator.and_ if (c[1] == "AND") else operator.or_)(
_interpret(c[0], s) if (type(c[0]) == list) else s[c[0]],
_interpret(c[2], s) if (type(c[2]) == list) else s[c[2]],
)
来源:https://stackoverflow.com/questions/52579218/propositional-logic-in-order-to-interpret-two-arguments