Passing data between a series of related functions - python

I am attempting to create an exam grading program. I successfully wrote each function to do what I need it to, but when I attempt to execute the entire program, I am running into issues with my return variables not being referenced.
Here is my code for context:
def userinput():
allinputs = []
while True:
try:
results = list(map(int, input('Exam points and exercises completed: ').split(' ')))
allinputs.append(results)
except:
ValueError
break
return allinputs
def points(allinputs):
exampoints = []
exercises = []
exercises_converted = []
gradepoints = []
counter = 0
for i in allinputs:
exampoints.append(i[0])
exercises.append(i[1])
for e in exercises:
exercises_converted.append(e//10)
for p in exampoints:
p2 = exercises_converted[counter]
gradepoints.append(p + p2)
counter += 1
return (gradepoints, exampoints, exercises_converted)
def average(gradepoints):
avg_float = sum(gradepoints) / len(gradepoints)
points_avg = round(avg_float, 1)
return points_avg
def pass_percentage(exercises_converted, exampoints):
failexam = []
passexam = []
passorfail = []
i = 0
while i < len(exampoints):
if exampoints[i] < 10 or exercises_converted[i] + exampoints[i] < 15:
failexam.append("fail")
passorfail.append(0)
else:
passexam.append("pass")
passorfail.append(1)
i += 1
percentage_float = len(passexam)/len(failexam)
percentage = round(percentage_float, 1)
return (percentage, passorfail)
def grades_distribution(passorfail, gradepoints):
grades = []
i = 0
l = 5
while i < len(gradepoints):
if passorfail[i] == 0:
grades.append(0)
elif passorfail[i] != 0 and gradepoints[i] >= 15 and gradepoints[i] <= 17:
grades.append(1)
elif passorfail[i] != 0 and gradepoints[i] >= 18 and gradepoints[i] <= 20:
grades.append(2)
elif passorfail[i] != 0 and gradepoints[i] >= 21 and gradepoints[i] <= 23:
grades.append(3)
elif passorfail[i] != 0 and gradepoints[i] >= 24 and gradepoints[i] <= 27:
grades.append(4)
elif passorfail[i] != 0 and gradepoints[i] >= 28 and gradepoints[i] <= 30:
grades.append(5)
i += 1
while l >= 0:
print(l, ": ", "*" * grades.count(l))
return
userinput()
print("Statistics:")
points(allinputs)
print(f"Points average: {average(gradepoints)}")
print(f"Pass percentage: {pass_percentage(exercises_converted, exampoints)}")
print("Grade distribution")
grades_distribution(passorfail, gradepoints)
I have no problems with the mechanics within each function; rather, my error lies where I try calling each of them from the main function.
The user input() function runs fine, and returns allinputs. However, when the second function points(allinputs) is called, the program states that the argument is undefined.

You should store the return value of a function before passing it as argument.
This should solve your problem
allinputs = userinput()
points(allinputs)

Related

How can I access value in another function when there is no return at python?

Currently I was stuck at my code and couldn't figure it out. My code is:
*def patientRegistration():
cont = "Y"
totalPCR = 0
totalAntigen = 0
totalChild = 0
totalSenior = 0
while cont == "Y":
print ("Please input your details below:")
name = input("Name:")
age = eval(input("Age:"))
gender = input("Gender[F/M]:")
type = eval(input("Type[1/2]:"))
if (type == 1):
#totalPCR += 1
if (age >= 1 and age <= 10):
totalChild += 1
totalPCR += 1
elif (age > 60):
totalSenior += 1
totalPCR += 1
elif (type == 2):
#totalAntigen += 1
if (age >= 1 and age <= 10):
totalChild += 1
totalAntigen += 1
elif (age > 60):
totalSenior += 1
totalAntigen += 1
cont= input("Cont[Y/N]:")
return totalPCR, totalAntigen, totalChild, totalSenior
def totalSales (totalPCR, totalAntigen, totalChildPCR, totalChildAntigen, totalSeniorPCR, totalSeniorAntigen):
pricePCR = 450
priceAntigen = 180
print ("Total Sales: RM")
print ("Breakdown of Sales -")
print ("PCR: RM")
print ("Antigen: RM")
return totalSales, pcrSales, antigenSales*
I would like to find out the totalChildPCR and so on, but I couldn't figure it out besides adding return at patientRegistration(). Is there any way I could make it without adding an extra return value at patientRegistration()?
You can do this by creating global varaible. when you create a variable inside a function, that variable is local, and can only be used inside that function. To create a global variable inside a function, you can use the global keyword.
def patientRegistration():
...
global totalChild = 0

list index out of range python 3.6

List index out of range error occurs at the line
if large_l[lg_index] ==small_l[sl_index]:
Here the code works fine when the values of following are,
correctword = "syria"
incorrectword = "siria"
but when assigning value as follows,
correctword = "syria"
incorrectword = "syri"
the above mentioned error has occurred. If could, tell me a way to get rid from this error.
Thank you
correctword = "syria"
incorrectword = "syri"
l1 = list(correctword)
l2 = list(incorrectword)
if len(l1) < len(l2):
large_l= l2
small_l = l1
else:
large_l =l1
small_l = l2
missmatchstart = False
lg_mismatch_start_index = 0
sl_mismatch_start_index = 0
lg_index = 0
sl_index = 0
del_count=0
add_count = 0
sub_count = 0
for l1_item in large_l:
for l2_item in small_l:
if large_l[lg_index] ==small_l[sl_index]:
if missmatchstart == False:
sl_mismatch_start_index = sl_index
lg_mismatch_start_index = lg_index
print(large_l[lg_index])
print("addition ")
print(add_count)
print("deletion ")
print(del_count)
print("substitution ")
print(sub_count)
if lg_index-lg_mismatch_start_index == sl_index-sl_mismatch_start_index:
sub_count += sl_index-sl_mismatch_start_index
lg_index+= 1
sl_index+= 1
elif lg_index-lg_mismatch_start_index > sl_index-sl_mismatch_start_index:
sub_count += sl_index-sl_mismatch_start_index
del_count += ((lg_index-lg_mismatch_start_index) - (sl_index-sl_mismatch_start_index))
lg_index+= 1
sl_index+= 1
elif lg_index-lg_mismatch_start_index < sl_index-sl_mismatch_start_index:
sub_count += lg_index-lg_mismatch_start_index
add_count += ((sl_index-sl_mismatch_start_index) - (lg_index-lg_mismatch_start_index))
lg_index+= 1
sl_index+= 1
missmatchstart = False
break
else:
print(large_l[lg_index])
if(missmatchstart == False):
lg_mismatch_start_index = lg_index
sl_mismatch_start_index = sl_index
print("missmatch large")
print(lg_mismatch_start_index)
print("missmatch small")
print(sl_mismatch_start_index)
missmatchstart =True
sl_index+=1
else:
sl_index+=1
if sl_index== len(small_l)-1:
lg_index +=1
sl_index = sl_mismatch_start_index
#del_count +=1
break
# elif lg_index == sl_index == len(small_l):
# sub_count +=
if lg_index >=len(large_l)-1:
del_count += len(large_l)- lg_index
#elif missmatchstart ==True:
print(add_count)
print(del_count)
print(sub_count)
You probably want to replace the condition on line 24:
if large_l[lg_index] ==small_l[sl_index]:
with:
if l1_item == l2_item:
There might be other bugs there, you should make your code more modular by splitting it into functions (in a reasonable matter) - it will be easier to maintain and debug!

Simulations in Evolutionary Biology - too many loops?

At the moment, I managed to code, successfully, a simulation for a work that I need to do. However, I'm fairly new to python. And so, I'm now in the process of making the simulation more efficient.
For instance:
if random.random() < mm:
z = numpy.random.choice(pat)
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][0] == 0:
malejuv[y][x][0] = 1
elif maleadult[z][0] == 1:
malejuv[y][x][0] = 0
else:
malejuv[y][x][0] = maleadult[z][0]
else:
if random.random() < mut:
if femaleadult[z][0] == 0:
malejuv[y][x][0] = 1
elif femaleadult[z][0] == 1:
malejuv[y][x][0] = 0
else:
malejuv[y][x][0] = femaleadult[z][0]
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][1] == 0:
malejuv[y][x][1] = 1
elif maleadult[z][1] == 1:
malejuv[y][x][1] = 0
else:
malejuv[y][x][1] = maleadult[z][1]
else:
if random.random() < mut:
if femaleadult[z][1] == 0:
malejuv[y][x][1] = 1
elif femaleadult[z][1] == 1:
malejuv[y][x][1] = 0
else:
malejuv[y][x][1] = femaleadult[z][0]
where:
mm - male dispersal,
mf - female dispersal,
mut - mutations,
pat - patch,
maleadult - adult male,
femaleadult - adult female,
malejuv - juvenile male,
femalejuv - juvenile female.
As you can see, the code is big. And this is only for males and when they disperse. The rest of the code is very similar. These are standard genetic and demographic processes - but I feel like this can be improved. I feel like these processes are simple enough, so maybe code as big as this is not necessary.
Does anyone have any ideas to shorten this and, by consequence, making it more efficient?
Your example does not have any loops but it looks like it could be simplified by one:
if random.random() < mm:
z = numpy.random.choice(pat)
for i in range(2):
if random.random() < 0.5:
if random.random() < mut:
if maleadult[z][i] == 0:
malejuv[y][x][i] = 1
elif maleadult[z][i] == 1:
malejuv[y][x][i] = 0
else:
malejuv[y][x][i] = maleadult[z][i]
else:
if random.random() < mut:
if femaleadult[z][i] == 0:
malejuv[y][x][i] = 1
elif femaleadult[z][i] == 1:
malejuv[y][x][i] = 0
else:
malejuv[y][x][i] = femaleadult[z][i]
It is also possible to pass a mutable object as reference to a function which can modify it, which allows further reduction of almost redundant code. I've added some data to test it:
#!python3
#coding=utf-8
import random
maleadult = [[["male adult"], ["another male adult"], ]]
femaleadult = [[["female adult"], ["another female adult"], ]]
malejuv = [[[["male juv"],["another male juv"]]]]
mut = 0.5
mm = 1.0
x = 0
y = 0
z = 0
def some_logic(a, j):
""" does something """
if random.random() < mut:
if a[z][i] == 0:
j[y][x][i] = 1
elif a[z][i] == 1:
j[y][x][i] = 0
# added!
else:
j[y][x][i] = 0
else:
j[y][x][i] = a[z][i]
if random.random() < mm:
z = 0 #numpy.random.choice(pat)
for i in range(2):
print(i)
if random.random() < 0.5:
some_logic(maleadult, malejuv)
else:
some_logic(femaleadult, malejuv)
print(maleadult)
print(malejuv)
print(femaleadult)

How do I run a binary search for words that start with a certain letter?

I am asked to binary search a list of names and if these names start with a particular letter, for example A, then I am to print that name.
I can complete this task by doing much more simple code such as
for i in list:
if i[0] == "A":
print(i)
but instead I am asked to use a binary search and I'm struggling to understand the process behind it. We are given base code which can output the position a given string. My problem is not knowing what to edit so that I can achieve the desired outcome
name_list = ["Adolphus of Helborne", "Aldric Foxe", "Amanita Maleficant", "Aphra the Vicious", "Arachne the Gruesome", "Astarte Hellebore", "Brutus the Gruesome", "Cain of Avernus"]
def bin_search(list, item):
low_b = 0
up_b = len(list) - 1
found = False
while low_b <= up_b and found == False:
midPos = ((low_b + up_b) // 2)
if list[midPos] < item:
low_b = midPos + 1
elif list[midPos] > item:
up_b = midPos - 1
else:
found = True
if found:
print("The name is at positon " + str(midPos))
return midPos
else:
print("The name was not in the list.")
Desired outcome
bin_search(name_list,"A")
Prints all the names starting with A (Adolphus of HelBorne, Aldric Foxe .... etc)
EDIT:
I was just doing some guess and check and found out how to do it. This is the solution code
def bin_search(list, item):
low_b = 0
up_b = len(list) - 1
true_list = []
count = 100
while low_b <= up_b and count > 0:
midPos = ((low_b + up_b) // 2)
if list[midPos][0] == item:
true_list.append(list[midPos])
list.remove(list[midPos])
count -= 1
elif list[midPos] < item:
low_b = midPos + 1
count -= 1
else:
up_b = midPos - 1
count -= 1
print(true_list)
Not too sure if this is what you want as it seems inefficient... as you mention it seems a lot more intuitive to just iterate over the entire list but using binary search i found here i have:
def binary_search(seq, t):
min = 0
max = len(seq) - 1
while True:
if max < min:
return -1
m = (min + max) // 2
if seq[m][0] < t:
min = m + 1
elif seq[m][0] > t:
max = m - 1
else:
return m
index=0
while True:
index=binary_search(name_list,"A")
if index!=-1:
print(name_list[index])
else:
break
del name_list[index]
Output i get:
Aphra the Vicious
Arachne the Gruesome
Amanita Maleficant
Astarte Hellebore
Aldric Foxe
Adolphus of Helborne
You just need to found one item starting with the letter, then you need to identify the range. This approach should be fast and memory efficient.
def binary_search(list,item):
low_b = 0
up_b = len(list) - 1
found = False
midPos = ((low_b + up_b) // 2)
if list[low_b][0]==item:
midPos=low_b
found=True
elif list[up_b][0]==item:
midPos = up_b
found=True
while True:
if found:
break;
if list[low_b][0]>item:
break
if list[up_b][0]<item:
break
if up_b<low_b:
break;
midPos = ((low_b + up_b) // 2)
if list[midPos][0] < item:
low_b = midPos + 1
elif list[midPos] > item:
up_b = midPos - 1
else:
found = True
break
if found:
while True:
if midPos>0:
if list[midPos][0]==item:
midPos=midPos-1
continue
break;
while True:
if midPos<len(list):
if list[midPos][0]==item:
print list[midPos]
midPos=midPos+1
continue
break
else:
print("The name was not in the list.")
the output is
>>> binary_search(name_list,"A")
Adolphus of Helborne
Aldric Foxe
Amanita Maleficant
Aphra the Vicious
Arachne the Gruesome
Astarte Hellebore

Binary Subtraction - Python

I want to make a binary calculator and I have a problem with the subtraction part. Here is my code (I have tried to adapt one for sum that I've found on this website).
maxlen = max(len(s1), len(s2))
s1 = s1.zfill(maxlen)
s2 = s2.zfill(maxlen)
result = ''
carry = 0
i = maxlen - 1
while(i >= 0):
s = int(s1[i]) - int(s2[i])
if s <= 0:
if carry == 0 and s != 0:
carry = 1
result = result + "1"
else:
result = result + "0"
else:
if carry == 1:
result = result + "0"
carry = 0
else:
result = result + "1"
i = i - 1
if carry>0:
result = result + "1"
return result[::-1]
The program works fine with some binaries subtraction but it fails with others.
Can someone please help me because I can't find the mistake? Thanks a lot.
Short answer: Your code is wrong for the case when s1[i] == s2[i] and carry == 1.
Longer answer: You should restructure your code to have three separate cases for s==-1, s==0, and s==1, and then branch on the value of carry within each case:
if s == -1: # 0-1
if carry == 0:
...
else:
...
elif s == 0: # 1-1 or 0-0
if carry == 0:
...
else:
...
else: # 1-0
if carry == 0:
...
else:
...
This way you have a separate block for each possibility, so there is no chance of overlooking a case like you did on your first attempt.
I hope the answer below it helps.
def binarySubstration(str1,str2):
if len(str1) == 0:
return
if len(str2) == 0:
return
str1,str2 = normaliseString(str1,str2)
startIdx = 0
endIdx = len(str1) - 1
carry = [0] * len(str1)
result = ''
while endIdx >= startIdx:
x = int(str1[endIdx])
y = int(str2[endIdx])
sub = (carry[endIdx] + x) - y
if sub == -1:
result += '1'
carry[endIdx-1] = -1
elif sub == 1:
result += '1'
elif sub == 0:
result += '0'
else:
raise Exception('Error')
endIdx -= 1
return result[::-1]
normalising the strings
def normaliseString(str1,str2):
diff = abs((len(str1) - len(str2)))
if diff != 0:
if len(str1) < len(str2):
str1 = ('0' * diff) + str1
else:
str2 = ('0' * diff) + str2
return [str1,str2]

Categories

Resources