Related
x = [d if d == z[i] and x[i] == "-" else x[i] for i in range(len(z))]
Can someone tell what this statement means by writing the long version?
That code is equivalent to this:
y = []
for i in range(len(z)):
if d == z[i] and x[i] == "-":
y.append(d)
else:
y.append(x[i])
x = y
This is the long version
y=[]
for i in range(len(z)):
if d == z[i] and x[i] == '-':
y.append(i)
else:
y.append(x[i])
So, for school, I got an exercise on recursion, which goes as follows:
I'm given a string and a random int value 'N'. The string is a boolean expression, for example '3*x - 2* y <0' . The result has to be a list of tuples(x, y), (-N < x < N and -N < y < N), from all the possible tuple combinations who meet the expression. I did this exercise first with for loops etc and that was not so difficult, but then I had to do it recursively, and here's where I got stuck:
As you can see, I just add up x and y by '1' at the end of the code, which will give me all tuple combinations where X and Y are the same. For example, if N = 5, my code only evaluates the combinations (-4,-4), (-3,-3) ... (4,4) but not (-2,1) or (1,3) for example. So my question is: can anyone help me writing a recursive code which evaluates the boolean expression in all the possible tuple combinations?
My code has to be written recursively and I can't use functions as 'itertools' etc, it's not allowed in our school.
**MY CODE:**
def solution(expression, N,x=None,y=None):
if x is None: x = -N + 1
if y is None: y = -N + 1
res = []
if x >= N and y >= N:
return []
if eval(expression) == True:
res.append((x, y))
return res + solution(expression, N, x+1, y+1)
I have modified your code and I think it works now:
UPDATE: I have corrected this expression if x < N - 1 : to that one if x < N - 1 or y < N - 1:
def solution(expression, N, x=None, y=None):
if x is None: x = -N + 1
if y is None: y = -N + 1
res = []
if eval(expression) == True:
res.append((x, y))
# if x < N - 1 :
if x < N - 1 or y < N - 1:
if y < N - 1:
y += 1
else:
x += 1
y = - N + 1
return res + solution(expression, N, x, y)
else:
return res
print(solution('3*x - 2* y <0', 4))
Slightly different approach building on getting permutations for a list and in the end checking the expression. Not the prettiest code but does the job.
results = []
def check(expression, items):
x = y = None
if len(items) == 1:
x = y = items[0]
if eval(expression) and (x, y) not in results:
results.append((x, y))
if len(items) == 2:
x = items[0]
y = items[1]
if eval(expression) and (x, y) not in results:
results.append((x, y))
x = items[1]
y = items[0]
if eval(expression) and (x, y) not in results:
results.append((x, y))
if len(items) > 2:
for i in items:
remaining_elements = [x for x in items if x != i]
check(expression, remaining_elements)
expression = "3*x - 2*y < 0"
N = 4
items = range(-N + 1, N)
check(expression, items)
print(results)
I am evaluating a postfix expression and I need it to say that the expression cannot be evaluated if there are too many operators one after the other. I understand there will be nothing in the stack so it cannot be evaluated but I don't know how to add it in my code.
I have only added here the code that I feel is necessary. If the code could be kept relatively similar that would be great.
edit: it is now just saying that anything cannot be evaluated
def process(testline,count):
k=[]
for i in range(0,len(testline),1):
if(testline[i].isdigit() == True):
k.append(float(testline[i]))
else:
try:
x = j.pop()
y = j.pop()
except IndexError:
break
if (testline[i]=='*'):
ans = x * y
k.append(ans)
elif (testline[i]=='+'):
ans = x + y
k.append(ans)
elif (testline[i]=='-'):
ans = x - y
k.append(ans)
elif (testline[i]=='/'):
ans = x / y
k.append(ans)
else:
print("Line",count,"is not able to be evaluated")
return
if len(k) != 1:
print("Line",count,"is not able to be evaluated")
else:
print ('Line',count,'result is',k[0])
return
print('Line',count,'result is',k[0])
Right now, the output is:
Line 1 is not able to be evaluated
Line 2 is not able to be evaluated
Line 3 is not able to be evaluated
Line 4 is not able to be evaluated
The input is:
295+*3-
61*7-4*
61*79-15*
6a*7-b*
623-+*-1
You could move your pops to the start of the iteration and surround with try/except to check that you can pop:
for i in range(0,len(testline),1):
if(testline[i].isdigit() == True):
k.append(float(testline[i]))
else:
try:
x = k.pop()
y = k.pop()
except IndexError:
break
if (testline[i]=='*'):
ans = x * y
k.append(ans)
elif (testline[i]=='+'):
ans = x + y
k.append(ans)
elif (testline[i]=='-'):
ans = x - y
k.append(ans)
elif (testline[i]=='/'):
ans = x / y
k.append(ans)
else:
print("Line",count,"is not able to be evaluated")
return
To make it more robust and don't need to add those extra appends I will do:
operators = {'*': lambda x ,y: x * y,
'/': lambda x, y: x / y,
'+': lambda x, y: x + y,
'-': lambda x, y: x - y}
for c in testline:
if c.isdigit():
k.append(float(c))
elif c in operators:
try:
x = k.pop()
y = k.pop()
except IndexError:
break
ans = operators[c](x, y)
k.append(ans)
else:
print("Line",count,"is not able to be evaluated")
return
EDIT: even simpler:
operators = {'*': lambda x ,y: x * y,
'/': lambda x, y: x / y,
'+': lambda x, y: x + y,
'-': lambda x, y: x - y}
for c in testline:
if c.isdigit():
k.append(float(c))
else:
try:
x = k.pop()
y = k.pop()
ans = operators[c](x, y)
k.append(ans)
except IndexError: # Couldn't pop... (empty stack)
break
except KeyError: # char is not a digit and not an operator
print("Line",count,"is not able to be evaluated")
return
Per the OP's desire to keep the original code as unchanged as possible, here's a version of the code that works with the most minimal of changes. The primary change, which is what the OP is asking about specifically, is to add checks for an inadequate number of operands before each arithmetic operation. This code also has the order of operands in calculations reversed where necessary:
def process(testline,count):
k=[]
for i in range(0,len(testline),1):
if(testline[i].isdigit() == True):
k.append(float(testline[i]))
elif (testline[i]=='*'):
if len(k) < 2:
print("Line", count, "is not able to be evaluated. not enough operands")
return
x = k.pop()
y = k.pop()
ans = x * y
k.append(ans)
elif (testline[i]=='+'):
if len(k) < 2:
print("Line", count, "is not able to be evaluated. not enough operands")
return
x = k.pop()
y = k.pop()
ans = x + y
k.append(ans)
elif (testline[i]=='-'):
if len(k) < 2:
print("Line", count, "is not able to be evaluated. not enough operands")
return
x = k.pop()
y = k.pop()
ans = y - x # << reversed operands
k.append(ans)
elif (testline[i]=='/'):
if len(k) < 2:
print("Line", count, "is not able to be evaluated. not enough operands")
return
x = k.pop()
y = k.pop()
ans = y / x # << reversed operands
k.append(ans)
else:
print("Line",count,"is not able to be evaluated")
return
if len(k) != 1:
print("Line",count,"is not able to be evaluated")
return
print('Line',count,'result is',k[0])
With this test code:
lines = [
'295+*3-',
'61*7-4*',
'61*79-15*',
'6a*7-b*',
'(-1)*2',
'623-+*-1',
]
for i in range(len(lines)):
process(lines[i], i + 1)
Resulting output is:
('Line', 1, 'result is', 25.0)
('Line', 2, 'result is', -4.0)
('Line', 3, 'is not able to be evaluated')
('Line', 4, 'is not able to be evaluated')
('Line', 5, 'is not able to be evaluated')
('Line', 6, 'is not able to be evaluated. not enough operands')
Here's my version, which is much like #Tomrikoo's second, but provides a complete answer and addresses a few additional problems with the original code. This code prints either the result or an error in all cases, and deals with the final state in both the case of a valid answer or an invalid stack condition (more than one item on the stack). Also, I reversed the order of application of the operands to be correct (I assume that '42/' should produce 2 rather than 0.5 like all my HP calculators would):
def process(testline, count):
operations = {
'+': lambda x, y: y + x,
'-': lambda x, y: y - x,
'*': lambda x, y: y * x,
'/': lambda x, y: y / x,
}
k = []
for c in testline:
if c.isdigit():
k.append(float(c))
elif c in operations:
if len(k) < 2:
print("Line {}: bad expression '{}' (not enough operands)".format(count, testline))
return
k.append(operations[c](k.pop(), k.pop()))
else:
print("Line {}: unexpected character '{}' in expression '{}'".format(count, c, testline))
return
if len(k) != 1:
print("Line {}: bad expression '{}' (too many operands)".format(count, testline))
else:
print("Line {}: Result: '{}' = {}".format(count, testline, k[0]))
lines = [
'295+*3-',
'61*7-4*',
'61*79-15*',
'6a*7-b*',
'(-1)*2',
'623-+*-1',
]
for i in range(len(lines)):
process(lines[i], i + 1)
Output:
Line 1: Result: '295+*3-' = 25.0
Line 2: Result: '61*7-4*' = -4.0
Line 3: bad expression '61*79-15*' (too many operands)
Line 4: unexpected character 'a' in expression '6a*7-b*'
Line 5: unexpected character '(' in expression '(-1)*2'
Line 6: bad expression '623-+*-1' (not enough operands)
for x in predRslt:
for y in actRslt:
if x == y and x =='1':
trueP += 1
elif x == y and x =='0':
trueN += 1
elif x != y and x == '1':
falseN += 1
elif x != y and x == '0':
falseP += 1
charNum += 1
totalActN = trueN + falseP
totalActP = falseN + trueP
totalPredN = trueN + falseN
totalPredP = trueP + falseP
print falseP
cmp_rslt('0110101001','1100100101')
actual output: 25
expected output: 2
Im trying to go through each string sequentailly from the beginning and compare the results. Then increment the corresponding TrueN, TrueP, FalseN, or FalseP.
for some reason, I keep getting an output of 25 when I should be getting way less than that because there's only 10 comparisons I should be making
you should iterate using the index of the first string like this:
for idx, x in enumerate(predRslt);
y = actRslt[idx]
if x == y and x =='1':
trueP += 1
elif x == y and x =='0':
trueN += 1
elif x != y and x == '1':
falseN += 1
elif x != y and x == '0':
falseP += 1
I tried looking on this site but i can't find exactly what's going wrong with my program. It makes it all the way to 13 or the data_list[25] but then it spits out that IndexError message.
def rlEncode(n, z, data_list):
while data_list[n] == data_list[n+1]:
z = z + 1
n = n + 1
while data_list[n] != data_list[n+1]:
return (n, z)
def unitTest( ):
counter = 0
n = 0
z = 1
data_list = [1,1,1,1,1,3,3,5,5,5,5,5,5,6,8,8,1,1,1,5,5,5,5,13,14, 14]
compress_list = [ ]
while counter < len(data_list):
rlEncode(n, z, data_list)
x, y = rlEncode(n, z, data_list)
compress = [data_list[x], y]
counter = counter + 1
compress_list = compress_list + compress
n = x+1
z = 1
continue
print("list: ", data_list)
print("compressed: ", compress_list)
In your rlEncode function, you are checking the while condition after incrementing n too high:
def rlEncode(n, z, data_list):
while data_list[n] == data_list[n+1]:
z = z + 1
n = n + 1
The first time you check data_list[n] == data_list[n + 1] it's ok ... but then you do n = n + 1, and go back to check the while condition. At this point, if n is 25, data_list[n + 1] will give you an index error, because data_list[25 + 1] does not exist.
You can check this by adding a print line like print(n, len(data_list)) just after n = n + 1.
So either make sure you only iterate from 0 to 24, or make sure you do something like:
if n == len(data_list) - 1:
break
You always have to keep the upper bounds of your arrays in mind when you are doing things like list[n + 1] anywhere in your algorithm.
Spoilers: Solution below:
In order to get your code working, I made two changes:
def rlEncode(n, z, data_list):
# Make sure we don't overrun our list length:
while n < len(data_list) - 1 and data_list[n] == data_list[n + 1]:
z += 1
n += 1
return (n, z)
def unitTest( ):
counter = 0
n = 0
z = 1
data_list = [1,1,1,1,1,3,3,5,5,5,5,5,5,6,8,8,1,1,1,5,5,5,5,13,14,14]
compress_list = []
while n < len(data_list) - 1: # Use n here, not counter
rlEncode(n, z, data_list)
x, y = rlEncode(n, z, data_list)
compress = [data_list[x], y]
counter = counter + 1
compress_list = compress_list + compress
n = x + 1
z = 1
print("list: ", data_list)
print("compressed: ", compress_list)
unitTest()
('list: ', [1,1,1,1,1, 3,3, 5,5,5,5,5,5, 6, 8,8, 1,1,1, 5,5,5,5, 13, 14,14])
('compressed: ', [1,5, 3,2, 5,6, 6,1, 8,2, 1,3, 5,4, 13,1, 14,2])