Easy way to check precedence of ( "and", "or") in python - python

I have a python list like this
[True, "and", False, "or", False, "or", True ....]
How to operate them and find the boolean value (True and False or False or True ...) efficiently ?
I know and has more precedence than or. So I know about the way where we break the list about every or and take or of booleans computed from each list.
I want to know is there a more easy way to do so ?
if my_list = [True, "and", False, "or", False, "or", True ] this will output
True as (True and False) or False or True = False or False or True which is True.
if my_list = [True, "and", True, "or", False, "or", False ] this will output
True as (True and True) or False or False = True or False or False which is True
if my_list = [False, "or", False, "and", False, "and", True ] = False or False which is False

One way to do operator precedence is through the shunting-yard algorithm, which requires a stack:
def evaluate(e):
ops = {'and': 1, 'or': 0}
op_stack = []
output = []
for i in e:
if i in ops:
while op_stack and ops[op_stack[-1]] > ops[i]:
output.append(op_stack.pop())
op_stack.append(i)
else:
output.append(i)
op_stack.reverse()
output.extend(op_stack)
stack = []
for i in output:
#print(stack, i)
if i in ops:
a, b = stack.pop(), stack.pop()
if i == 'and':
i = a and b
else:
i = a or b
stack.append(i)
return stack[0]
>>> evaluate([True, "and", False, "or", False, "or", True])
True
>>> evaluate([True, 'or', True, 'and', False])
True
The other way to do operator precedence is a recursive precedence climbing algorithm:
ops = {'and': 1, 'or': 0}
def tokenizer(l):
for i in l:
o = yield i
while o:
yield None
o = yield o
def evaluate(token, prec=0):
lhs = next(token)
while True:
op = next(token, None)
if op is None or ops[op] < prec:
if op: token.send(op)
break
rhs = evaluate(token, ops[op]+1)
#print(lhs, op, rhs)
lhs = lhs and rhs if op == 'and' else lhs or rhs
return lhs
>>> evaluate(tokenizer([True, 'or', True, 'and', False]))
True
>>> evaluate(tokenizer([True, "and", False, "or", False, "or", False, "or",
... True, "and", False, "or", False, "or", False]))
False
With the prints:
>>> evaluate(tokenizer([True, "and", False, "or", False, "or", False, "or",
... True, "and", False, "or", False, "or", False]))
True and False
False or False
False or False
True and False
False or False
False or False
False or False
False

Not sure if this will be faster, but:
l = [True, "and", False, "or", False, "or", False, "or", True, "and", False, "or", False, "or", False]
eval(' '.join([ str(z) for z in l]))
result:
False

IIUC you could use map, isinstance:
l = [True, "and", False, "or", False, "or", True]
res = list(map(lambda x: isinstance(x, bool), l))
print(res)
[True, False, True, False, True, False, True]

If I understand correctly this should be the simplest (less elegant) solution
expression = [True, "and", False, "or", False, "or", True]
def eval_expr( value1, operator, value2):
if operator == 'and':
return value1 and value2
else:
return value1 or value2
result = None
while len(expression) != 1:
v1 = expression.pop()
op = expression.pop()
v2 = expression.pop()
partial_result = eval_expr(v1, op, v2)
expression.insert(0, partial_result)
result = partial_result
print result

#Iliyan 's answer is correct. Less hacky than me.
I came up with a trick to do so.
my_list = [True, "and", False, "or", False, "or", True]
I created a file temp.py
Entered all values in list of my_list in order space separated in temp.py
Executed temp.py
Deleted temp.py
Kind of a hack ;)

Related

Understanding recursive canSum function

I have a function, which, given a number and a list of numbers returns if the number can be made out of the
numbers in a list, where numbers can be used as many times as needed:
def canSum(target_sum, numbers, memo = {}):
if target_sum in memo:
return memo[target_sum]
if target_sum == 0:
return True
if target_sum < 0:
return False
for n in numbers:
remainder = target_sum - n
if canSum(remainder, numbers) == True:
memo[target_sum] = True
return True, memo
memo[target_sum] = False
return False,memo
It should return True and False depending if the target_sum can be made by adding any numbers any amount of time in the numbers list.
For example canSum(4, [2]) should return True because 2+2 is 4 and so on.
However I can't understand where is my mistake, all of the below should return True.
canSum(4,[2])
# (False, {2: True, 4: False})
canSum(4,[2,1])
# (False, {2: True, 1: True, 3: True, 4: False})
canSum(4,[1,2])
# (True, {1: True, 2: True, 3: True, 4: True})
canSum(10,[2])
# (False, {2: True, 4: False, 6: False, 8: False, 10: False})
canSum(10,[2,3])
# (False, {2: True, 1: False, 4: False, 3: True, 6: False, 5: True, 8: False, 7: True, 10: False})
Also, is there a difference or a need to pass memo to the recursive function call? Which does not seem to make any difference.
if canSum(remainder, numbers) == True: # -> if canSum(remainder, numbers, memo) == True:
memo[target_sum] = True
return True, memo
Consider when you call canSum(0, [2]), the function will be return literal True. and if canSum(0, [2]) == True condition's will be satisfy. but when you call canSum(2, [2]), the function will be return a tuple of (True, {2: True}) and if canSum(2, [2]) == True condition's won't be satisfy. So when you call canSum(4, [2]), the function will return (False, {2: True, 4: False}).
You have to return in same format for every calls. I think this will be work.
def canSum(target_sum, numbers, memo={}):
if target_sum in memo:
return memo[target_sum], memo
if target_sum == 0:
return True, memo
if target_sum < 0:
return False, memo
for n in numbers:
remainder = target_sum - n
if canSum(remainder, numbers)[0]:
memo[target_sum] = True
return True, memo
memo[target_sum] = False
return False, memo

I am having a problem with my code on Sieve of Eratosthenes

See my code below. I keep getting an error code, and I don't understand what it means too. Where in the code can I look?
def list_true(n):
return [False for x in range(2)] + [x for x in range (2, n+1)]
assert len(list_true(20)) == 21
assert list_true(20)[0] is False
assert list_true(20)[1] is False
def mark_false(bool_list, p):
mark_false = []
for x in bool_list:
if x/p == 1:
mark_false.append(True)
elif x % p == 0:
mark_false.append(False)
else:
mark_false.append(True)
return mark_false
assert mark_false(list_true(6), 2) == [False, False, True, True, False, True, False]
def find_next(bool_list, p):
x = 0
cleared = False
for bool in bool_list:
if cleared:
if bool:
return x
if x == p and bool:
cleared = True
x += 1
return None
assert find_next([True, True, True, True], 2) == 3
assert find_next([True, True, True, False], 2) is None
def prime_from_list(bool_list):
y = [x for x, i in enumerate(bool_list) if i]
prime_from_list = []
for element in bool_list:
if element == True:
return y
return prime_from_list
assert prime_from_list([False, False, True, True, False]) == [2, 3]
def sieve(n):
bool_list = list_true(n)
p = 2
while p is not None:
bool_list = mark_false(bool_list, p)
p = find_next(bool_list, p)
return prime_from_list(bool_list)
Then I get an error message after the below code.
assert sieve(1000) == get_primes(0, 1000)
--------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-50-c49169fabbae> in <module>()
----> 1 assert sieve(1000) == get_primes(0, 1000)
AssertionError:
Why am I getting the error and is there a possible way I can amend it?
This is a strange question. First, you didn't supply get_primes(0, 1000) so we can't compare the results. Second, you, as programmer, put in the assert statements to test for situations you know shouldn't happen, so you shouldn't question the assert itself.
I believe the reason the assert is failing is that your tortured code doesn't produce primes (it includes composite odd numbers) E.g. sieve(20) returns:
[2, 3, 5, 7, 9, 11, 13, 15, 17, 19]
Furthermore, your code isn't actually a sieve! The mark_false() routine should simply strike out multiples of the most recently discovered prime, but instead it tests all the numbers to see if they are divisible by the prime! This is brute force prime searching in the guise of a sieve.
Below is my rework and simplification of your code which should pass the assertion in question:
def list_true(n):
return [False for _ in range(2)] + [True for _ in range(2, n + 1)]
assert len(list_true(20)) == 21
assert list_true(20)[0] is False
assert list_true(20)[19] is True
def mark_false(bool_list, prime):
for index in range(prime * prime, len(bool_list), prime):
if bool_list[index] is False:
continue
bool_list[index] = False
return bool_list
assert mark_false(list_true(6), 2) == [False, False, True, True, False, True, False]
def find_next(bool_list, index):
while index + 1 < len(bool_list):
index += 1
if bool_list[index]:
return index
return None
assert find_next([True, True, True, True], 2) == 3
assert find_next([True, True, True, False], 2) is None
def prime_from_list(bool_list):
return [index for index, boolean in enumerate(bool_list) if boolean]
assert prime_from_list([False, False, True, True, False]) == [2, 3]
def sieve(number):
bool_list = list_true(number)
prime = 2
while prime is not None:
bool_list = mark_false(bool_list, prime)
prime = find_next(bool_list, prime)
return prime_from_list(bool_list)
assert sieve(1000) == get_primes(0, 1000)
Note that bool is a Python class, don't use it as a variable name.

Make loop def for varying sizes

So I´m making a basic truth table function. In this example, the formula has 4 values and thus needs 4 loops. Is there any way for me to make a def that takes the number of values in the formula and makes a loop for it?
def Formula1(a,b,c,d):
return ((a & c) | (b & c) | (d & c))
for a in range(0,2):
for b in range(0,2):
for c in range(0, 2):
for d in range(0, 2):
#printtable(a,b,c,d)
print(a,b,c,d,"=",Formula1(a,b,c,d))
For instance here the formula has 5 values and needs 5 loops.
def Formula2(a,b,c,d,e):
return ((not a & b) | (c & b) | (d & (not e)))
Using itertools:
import itertools
def Formula1(a, b, c, d):
return ((a & c) | (b & c) | (d & c))
if __name__ == '__main__':
table = list(itertools.product([False, True], repeat=4))
for a,b,c,d in table:
print("{}, {}, {}, {} = {}".format(a, b, c, d, Formula1(a, b, c, d))
Result (table is all the combinations):
False, False, False, False = False
False, False, False, True = False
False, False, True, False = False
False, False, True, True = True
False, True, False, False = False
False, True, False, True = False
False, True, True, False = True
False, True, True, True = True
True, False, False, False = False
True, False, False, True = False
True, False, True, False = True
True, False, True, True = True
True, True, False, False = False
True, True, False, True = False
True, True, True, False = True
True, True, True, True = True

Removing things from a list correctly

I am currently working on making an Akinator-like game that currently only does Zelda Breath of the Wild species. For some reason, when I enter all of the information for coocoo, the output is Gerudo. Please help. Here is the code:
class Thing(): # The general class for a object
def __init__(self, area, race, ally, living, extra):
self.area = area
self.race = race
self.ally = ally
self.living = living
self.extra = extra
class Guess(): # The class for the guess
def __init__(self):
self.area = None
self.race = None
self.ally = bool
self.living = bool
self.extra = str
talus = Thing("everywhere", "talus", False, True, " rocky")
coocoo = Thing("everywhere", "coocoo", True, True, " a fierce, chicken-like friend")
zora = Thing("in the zora area", "zora", True, True, " swimming")
rito = Thing("in the rito area", "rito", True, True, " flying")
goron = Thing("in the goron area", "goron", True, True, " rolling")
gerudo = Thing("in the gerudo area", "gerudo", True, True, " a women")
hylean = Thing("everywhere", "hylean", True, True, " good and bad")
guardian = Thing("everywhere", "guardian", False, False, " mechanical")
moblin = Thing("everywhere", "moblin", False, True, " related to the bokoblin")
staloblin = Thing("everywhere", "staloblin", False, False, " a large undead enemy")
bokoblin = Thing("everywhere", "bokoblin", False, True, " a basic enemy")
stalkoblin = Thing("everywhere", "stalkoblin", False, False, " a basic undead enemy")
lynel = Thing("everywhere", "lynel", False, True, " a horse-like beast")
octorok = Thing("everywhere", "octorok", False, True, " a rock-shooting monster")
lizafos = Thing("everywhere", "lizafos", False, True, " a scaley, speeding, baddie")
stalzafos = Thing("everywhere", "stalzafos", False, False, " a fast, skeletal enemy")
spirit = Thing("everywhere", "spirit", True, False, " a helpful ghost")
def akinator():
everything = [talus, zora, rito, goron, gerudo, hylean, guardian, moblin, stalkoblin, staloblin, bokoblin, lynel, octorok, lizafos, stalzafos, spirit, coocoo]
possible_areas = ["everywhere", "in the zora area", "in the rito area", "in the goron area", "in the gerudo area", "in the hylean greenlands"]
guess = Guess()
alive = input("Is it alive? y/n ")
if alive == "n":
guess.living = False
elif alive == "y":
guess.living = True
for i in everything:
if i.living != guess.living:
everything.pop(everything.index(i))
ally = input("Is it one of your allies? y/n ")
if ally == "n":
guess.ally = False
elif ally == "y":
guess.ally = True
for i in everything:
if i.ally != guess.ally:
everything.pop(everything.index(i))
for i in possible_areas:
area = input("Do they live " + i + "? y/n ")
if area == "y":
guess.area = i
break
for i in everything:
if i.area != guess.area:
everything.pop(everything.index(i))
for i in everything:
extra = input("Is it" + i.extra + "? y/n ")
if extra == "n":
everything.pop(everything.index(i))
if extra == "y":
print("Is it a "+ i.race +"?")
quit()
print("Is it a "+everything[0].race+"?")
akinator()
Popping items from a list while you are iterating over it is a bad idea - it fouls up your list iterator, so you skip testing the following item.
Instead of
for i in everything:
if i.living != guess.living:
everything.pop(everything.index(i)) # <- BAD
try
everything = [i for i in everything if i.living == guess.living]

Python dict using logic input for truth tables

Alright boys and girls here we go. To start off I have a couple of questions. Since my program is large I will simply ask questions in stages, this question being the first. I'm creating a program that generates a truth table for postfix logical expressions. Here are the operators allowed and their logical equivalents:
Operators:
= Logical Equivalence (≡ or ↔)
`->` or `<=` Logical Implication (→)
+ Disjunction (∨), AKA “or”
* Conjunction (∧), AKA “and”
`~` or `!` Negation (¬), AKA “not”
Here are some examples of input and output:
input
p True =
output
p p True =
False False
True True
input
p !
output
p p !
False True
True False
input
p q =
output
p q p q =
False False True
False True False
True False False
True True True
Ok I don't really know where to begin, but I'm not asking for anybody to write this program for me. I know I need to write code using a Python dict, that matches the keys to the corresponding proposition. But how do I know which ones to put for keys and which ones to put for values? Also, in the case of:
`->` or `<=` Logical Implication (→)
and
`~` or `!` Negation (¬), AKA “not”
How do I assign 2 different inputs to be able to be used in a python dict? I hope this isn't too confusing, I'm very noob at python, any help is appreciated. Thank you!
UPDATE
Ok here is the code I have now:
propositions = {
'=' : (2, {(True, True): True,
(True, False): False,
(False, True) : False,
(False, False): True,
}),
'->' : (2, {(True, True): True,
(True, False): False,
(False, True): True,
(False, False): True,
}),
'+' : (2, {(True, True): True,
(True, False): True,
(False, True): True,
(False, False): False,
}),
'*' : (2, {(True, True): True,
(True, False): False,
(False, True): False,
(False, False): False,
}),
'!' : (1, {True: False,
False: True})}
prop = sys.stdin.readline()
prop = prop.split()
prop = prop[::-1]
for x in prop:
I believe I successfully reversed the string and removed all whitespaces, but I am still a bit confused on iterating through it.
SECOND UPDATE here is my code:
propositions = {
'=' : (2, {(True, True): True,
(True, False): False,
(False, True) : False,
(False, False): True,
}),
'->' : (2, {(True, True): True,
(True, False): False,
(False, True): True,
(False, False): True,
}),
'+' : (2, {(True, True): True,
(True, False): True,
(False, True): True,
(False, False): False,
}),
'*' : (2, {(True, True): True,
(True, False): False,
(False, True): False,
(False, False): False,
}),
'!' : (1, {True: False,
False: True})}
prop = sys.stdin.readline()
prop = prop.strip().split()
prop = reversed(prop)
def evaluate():
token = next(prop)
try:
nargs, table = propositions[token]
except KeyError:
if token.lower() in ('true', '1'):
return True
elif token.lower() in ('false', '0'):
return False
else:
return token
return table[tuple(evaluate() for i in range(nargs))]
You have to build your dicts in the order of resolution from outer to inner:
master_dict = {
'=': (2, {(True, True): True,
(True, False): False,
...
}),
...
'!': (1, {True: False,
False: True})}
The numbers indicate how many operands the operator takes.
To parse an input read it from right to left.
Use a recursive function, that consumes one token from the right.
(1) If the token is an operator (i.e. a key in your dictionary) retrieve the corresponding value from your master dict.
The number stored first is the number of arguments the operator takes. So your function must now call itself as many times as there are arguments. Be sure to keep track of which tokens have already be read. One neat way of doing this is using a list iterator, which will spit out each element exactly once, so you can't get the indexing wrong. Once you have all the arguments you apply the truth table you've just retrieved, read out the result and return it.
(2) If the token is not an oprator your function must just return it.
prop = sys.stdin.readline()
def solve_no_var(prop):
rev_iter = reversed(prop)
def evaluate():
token = next(rev_iter)
try:
nargs, table = propositions[token]
except KeyError:
if token.lower() in ('true', '1'):
return True
elif token.lower() in ('false', '0'):
return False
else:
return token
return table[tuple(evaluate() for i in range(nargs))]
return evaluate()
def solve(prop):
prop = prop.strip().split()
variables = list(set(prop) - set(propositions)
- {'True', 'TRUE', 'true', '1', 'False', 'FALSE', 'false', '0'})
lookup = {v: [j for j, p in enumerate(prop) if p == v] for v in variables}
N = len(variables)
print((N*" {:6} ").format(*variables), 'result')
for p in itertools.product(("True", "False"), repeat=N):
prop_nv = prop.copy()
for v, b in zip (variables, p):
for j in lookup[v]:
prop_nv[j] = b
res = solve_no_var(prop_nv)
print(((N+1)*" {:6} ").format(*(p + (res,))))
solve(prop)

Categories

Resources