How to make a table with 3 data sets? - python

I've been going at this for a while but I'm not quite sure how to tackle it. I have three data sets- scores (A-F, counts the number of grades in each rank), count (the program prints a table of count by rank), and Percentage (dividing the count by the total in the data set to get the percentage in each rank).
The end result should look similar to this given 7 grades (integers).
(example user inputted data: [88, 76, 89, 78, 74, 87, 95])
>>> GRADE COUNT PERCENTAGE
>>> A 2 28.6%
>>> B 2 28.6%
>>> C 3 42.9%
>>> D 0 0%
>>> F 0 0%
Currently, this is my long, tedious, elementary code. I'm having a hard time with executing and making it work correctly and I probably am not making it work properly at all.
def grade_scores(scoreList):
for score in scoreList: #shows the scores in the score list, uses ddata from previous function
if score >= 91:
Ascore = 'A'
Acount +=1
sum(Ascore) / Acount len(scoreList) = Apercentage
elif score >= 81 and score <=90:
Bscore = 'B'
Bcount +=1
sum(Bscore) / Bcount len(scoreList) = Bpercentage
elif score >= 71 and score <=80:
Cscore = 'C'
Ccount +=1
sum(Cscore) / Ccount len(scoreList) = Cpercentage
elif score >= 61 and score <=70:
Dscore = 'D'
Dcount +=1
sum(Dscore) / Dcount len(scoreList) = Dpercentage
else:
Fscore = 'F'
Fcount +=1
sum(Dscore) / Dcount len(scoreList) = Dpercentage
for i in range(scoreList):
print ('Grade', '\t', 'Count', '\t', 'Percentage')
print(Ascore, end="\t", Acount, end="\t", Apercentage)
print(Bscore, end="\t", Bcount, end="\t", Bpercentage)
print(Cscore, end="\t", Ccount, end="\t", Cpercentage)
print(Dscore, end="\t", Dcount, end="\t", Dpercentage)
print(Fscore, end="\t", Fcount, end="\t", Fpercentage)
I would hope to make it more of a grid style instead but I don't think it is formatted correctly and does not seem to work properly ( I also get an error about "len" in the 6th line). I appreciate any input on this.

Not completely sure what you meant by the question, but first, the error message is most likely caused by a TypeError, because you are using the variable scoreList in the range() function (which takes in integers, and integers have no length).
Also you may want to consider to utilize lists to organize the data better.
For the grid style, you should use the .format() method to help you with printing the lines:
# Assuming you have 3 lists:
# grade = ['A','B','C','D','E']
# count = [2, 2, 3, 0, 0] Have another function capture user input
# and convert it into this list.
# percentage = [28.6, 28.6, 42.9, 0, 0] Same as above ^
print("SCORE COUNT PERCENTAGE")
for i in range(len(grade)):
print(" {} {} {} %".format(grade[i], count[i], percentage[i]))
For the elif conditionals, you would have to stick with what you already have. However, you may want to modify the variable names a bit, as a better way to do this is through lists:
for i in range(len(gradeInputList)):
if grade >= 90:
count[0] += 1 # Increase index 0 (Corresponds to value A) by 1
elif grade >= 80 and < 90:
count[1] += 1
# Omitted code here, you get the idea
# ...
else:
count[4] += 1
And at the end you could have another for loop that calculates the average:
for i in range(len(count)):
average[i] = count[i] / sum(count) * 100 # Calculates the percentage
Whew, hope this helped! :)

If you want to print something in grid format then use tabulate package. It is easy and convinient . Here is sample code :
from tabulate import tabulate
table = [["spam",42],["eggs",451],["bacon",0]]
headers = ["item", "qty"]
print tabulate(table, headers, tablefmt="grid")
This prints :
+--------+-------+
| item | qty |
+========+=======+
| spam | 42 |
+--------+-------+
| eggs | 451 |
+--------+-------+
| bacon | 0 |
+--------+-------+

Related

Trying to use zfill and increment characters with Python

Hello lovely stackoverflowians!
I am fairly new to programming. Only have been programming a little under 2 months using CS50 which uses C and MITx Python. I went on Codewars and am trying to solve a problem where you basically get an id and then come out with a license plate number like this aaa001...aaa999, aab001...zzz999
if you catch my drift. For some reason my code compiles but when I run it I get this error.
File "/Users/pauliekennedy/Desktop/temp.py", line 9, in find_the_number_plate
a_str = (a_numb.zfill(3), range(0, 10))
AttributeError: 'int' object has no attribute 'zfill'
Because of this I am not able to test my code. If you could help me with this problem I would be much appreciated. As well, if you have anything to say about my code in general, tips, advice how to make it better, and if it will achieve this goal at all. Here is my code thanks again all.
#set number to 1 to start
a_numb = 1
#incrementing loop when 999 go back set back 0
while a_numb <1001:
a_numb += 1
a_str = str(a_numb)
# giving the number 00 or just 0 in front
if a_numb < 100:
a_str = (a_numb.zfill(3), range(0, 10))
#resetting the number back to 1
if a_numb == 999:
a_numb = 1
# Setting i to 0 and incrementing the characters
i = 0
ch = 'a'
ch2 = 'a'
ch3 = 'a'
#looping through alphabet
for i in range(26):
ch = chr(ord(ch) + 1)
print(ch)
if i == 26:
i = 0
if ch == 'z':
ch2 = chr(ord(ch) + 1)
if ch == 'z' & ch2 == 'z':
ch3(ord(ch) + 1)
# Adding results together and returning the string of them all
letter_plate = str(ch3 + ch2 + ch)
plate = str(a_numb) + str(letter_plate)
return plate```
Maybe you could consider using f-string string formatting instead:
def find_the_number_plate(customer_id):
number_part = customer_id % 999 + 1
customer_id //= 999
letter_part = ['a', 'a', 'a']
i = 0
while customer_id:
letter_part[i] = chr(ord('a') + customer_id % 26)
customer_id //= 26
i += 1
return f"{''.join(letter_part)}{number_part:03}"
You could use product from itertools to form the license plate numbers from 3 letters and numbers from 1 to 999 formatted with leading zeros:
from itertools import product
letter = "abcdefghijklmnopqrstuvwxyz"
numbers = (f"{n:03}" for n in range(1,1000))
plates = [*map("".join,product(letter,letter,letter,numbers))]
for plate in plates: print(plate)
aaa001
aaa002
aaa003
aaa004
aaa005
aaa006
aaa007
aaa008
...
If you only need to access a license place at a specific index, you don't have to generate the whole list. You can figure out which plate number will be at a given index by decomposing the index in chunks of 999,26,26,26 corresponding to the available option at each position/chunk of the number.
def plate(i):
letter = "abcdefghijklmnopqrstuvwxyz"
result = f"{i%999+1:03}"
i //= 999
for _ in range(3):
result = letter[i%26] + result
i //= 26
return result
output:
for i in range(10):print(plate(i))
aaa001
aaa002
aaa003
aaa004
aaa005
aaa006
aaa007
aaa008
aaa009
aaa010
plate(2021) # aac024

Check if variable changes in for loop in Python

I have this code here and I'm looking for a way to check if min_score and max_score changes, and count how many times it changes. I can't seem to find a way to do it:
games = int(input())
score = list(input().split())
score = [int(x) for x in score]
for y in range(1, len(score) + 1):
min_score = (str(min(score[:y])) + " MIN")
max_score = (str(max(score[:y])) + " MAX")
print(min_score)
print(max_score)
This is a sample test case for reference:
9
10 5 20 20 4 5 2 25 1
First number is the size of the array, which in my code I never use because I make an array just from the string of numbers below ( in fact I don't even know why they give the size).
Basically I need to find how many times the max and min values change. I'm still a beginner in programming and I don't really know what to do..
you could just keep track of the lowest and highest number encountered and check if the current score is just below or above. A simple script could look like this:
scores = [10,5,20,20,4,5,2,25,1]
countChanges = 0
limitLow = float("inf")
limitHigh = -float("inf")
for s in scores:
if(s < limitLow):
countChanges += 1
limitLow = s
if(s > limitHigh):
countChanges += 1
limitHigh = s
print("current score: %3d limits: [%2d .. %2d] changes:%d" % (s, limitLow, limitHigh, countChanges))
spam = [10, 5, 20, 20, 4, 5, 2, 25, 1]
print(sum(n < min(spam[:idx]) for idx, n in enumerate(spam[1:], start=1)))
print(sum(n > max(spam[:idx]) for idx, n in enumerate(spam[1:], start=1)))
output
4
2
if you also want to account for initial value - add 1.
Looks like a hankerrank problem? They often give the length of the input to allow solutions without knowing about built-in methods like len().
Anyway,
You can initialise min and max to the first element of the array (if it exists, check the specification), or some suitably small and large values (again, check the possible values).
Then you can count the number of times min and max changes as you go.
Should be easy enough to adapt for the case that you just want to track any change, not min and max separately. It wasn't clear from your question.
scores = [10, 5, 20, 20, 4, 5, 2, 25, 1]
min_score = scores[0]
max_score = scores[0]
min_score_changes = 0
max_score_changes = 0
for score in scores:
if score < min_score:
min_score = score
min_score_changes += 1
if score > max_score:
max_score = score
max_score_changes += 1
I solved it like this after some thinking:
games = int(input())
score = list(input().split())
score = [int(x) for x in score]
min_score_list, max_score_list = [] , []
for y in range(1, len(score) + 1):
min_score = (min(score[:y]))
max_score = (max(score[:y]))
if min_score not in min_score_list:
min_score_list.append(min_score)
if max_score not in max_score_list:
max_score_list.append(max_score)
print((len(max_score_list) - 1), len(min_score_list) - 1)
I know it's not perfect code but at least I did myself :D

Using lists to calculate grades Python 3, help simplifying code

I need help/input on a homework assignment that I have. I already have a code that works but I was wondering if there was a simpler way to write the code to make it less lengthy.
Here are the directions for the assignment for reference:
There are ten names and five lists of test scores. The correspondence
between the names and the test scores are determined by positions. For example, the test scores for Cindy are 67, 92, 67, 43, 78. Drop the lowest of the five test scores for each student and average the rest and determine the letter grade for that student. Make sure your printout is the same as mine with the same column widths.
Here is my code:
names = ['April','Bill','Cindy','Dave','Emily', 'Frank','Gene','Hank','Irene','Jeff']
test1 = [34,21,67,45,88, 77,63,96,89,88]
test2 = [11,67,92,35,89, 25,78,94,81,63]
test3 = [94,33,67,34,67, 88,55,99,23,43]
test4 = [27,83,43,67,93, 45,67,77,86,90]
test5 = [43,76,78,45,65, 99,65,65,79,43]
total = [0,0,0,0,0,0,0,0,0,0]
min = [0,0,0,0,0,0,0,0,0,0]
percent = [0,0,0,0,0,0,0,0,0,0]
grade = ['F','F','F','F','F','F','F','F','F','F']
for i in range (10):
total[i] = test1[i]
min[i] = test1[i]
for i in range (10):
total[i] = total[i] + test2[i]
total[i] = total[i] + test3[i]
total[i] = total[i] + test4[i]
total[i] = total[i] + test5[i]
min[i] = min[i] if min[i] < test2[i] else test2[i]
min[i] = min[i] if min[i] < test3[i] else test3[i]
min[i] = min[i] if min[i] < test4[i] else test4[i]
min[i] = min[i] if min[i] < test5[i] else test5[i]
total[i] = total[i] - min[i]
for i in range (10):
percent[i] = total[i]/4.0
if percent[i] >= 90: grade[i] = 'A'
elif percent[i] >= 80: grade[i] = 'B'
elif percent[i] >= 70: grade[i] = 'C'
elif percent[i] >= 60: grade[i] = 'D'
elif percent[i] >= 50: grade[i] = 'F'
print (" %s\t%d %2.2f %s \n" %(names[i], total[i], percent[i], grade[i]))
The output should look like this:
April 198 49.50 F
Bill 259 64.75 D
Cindy 304 76.00 C
Dave 192 48.00 F
Emily 337 84.25 B
Frank 309 77.25 C
Gene 273 68.25 D
Hank 366 91.50 A
Irene 335 83.75 B
Jeff 284 71.00 C
Basically I just wanted to know if anyone had any ideas/methods for me to try in order to simplify the the code. I just get confused since the grades correspond vertically. It is good either way but I feel as if it could be modified. I am still somewhat a beginner, so I may not be familiar with what could be a simple fix :) Thanks!
This is an ideal use case for dictionaries rather than lists. Dictionaries allow you to assign values to keys. In this case, the keys would be the student names and the values their grades. E.g.,
{student_1 : [grade_1, grade_2 ... grade_n],
...
student_n : [grade_1, grade_2 ... grade_n]
}
In this way it would be much easier to associate grades with any given student.
Also, some very basic function definitions (e.g. average grade) would be very helpful here. These prove to be super useful to create a clean output using an f-string.
In summary: looking up dictionaries, functions and f-strings could teach you a lot of useful skills for further coding. I have included an example below, hope it is somewhat understandable.
names = ['April','Bill','Cindy','Dave','Emily',
'Frank','Gene','Hank','Irene','Jeff']
test1 = [34,21,67,45,88, 77,63,96,89,88]
test2 = [11,67,92,35,89, 25,78,94,81,63]
test3 = [94,33,67,34,67, 88,55,99,23,43]
test4 = [27,83,43,67,93, 45,67,77,86,90]
test5 = [43,76,78,45,65, 99,65,65,79,43]
#Assign every student to the dictionary
#So far their respective grades are an empty list
grades = dict()
for name in names:
grades[name] = []
#Group all tests in a single list, which is easier to iterate over
tests = [test1, test2, test3, test4, test5]
#Loop over all tests
#Every i-th student gets the i-th value of every test added to the dictionary
for test in tests:
for i in range(len(test)):
grades[names[i]].append(test[i])
#Remove the lowest grade and calculate the average afterwards
def avg_grade(grades):
grades.remove(min(grades))
return sum(grades) / len(grades)
#Associate a grade with a letter compared to a threshold
def letter(grade):
thresholds = [90, 80, 70, 60, 50]
letters = ['A', 'B', 'C', 'D', 'F']
for i in range(len(thresholds)):
if grade >= thresholds[i]:
return letters[i]
#Output as f-string
for name in names:
print(f'{name:6} {avg_grade(grades[name]):.2f} '
f'{letter(avg_grade(grades[name]))}')

Python if condition for print or not print

Here is a basic math problem. I want to calculate least amount of banknotes to be paid.
Here is my code and working well.
total_payment = int(input("Please enter the total amount: "))
Dollar50 = int(total_payment // 50)
remaining_money = total_payment % 50
Dollar20 = int(remaining_money // 20)
remaining_money = remaining_money % 20
Dollar10 = int(remaining_money // 10)
remaining_money = remaining_money % 10
Dollar5 = int(remaining_money // 5)
remaining_money = remaining_money % 5
Dollar1 = int(remaining_money // 1)
print("We need {0} 50 dollar.".format(Dollar50))
print("We need {0} 20 dollar.".format(Dollar20))
print("We need {0} 10 dollar.".format(Dollar10))
print("We need {0} 5 dollar.".format(Dollar5))
print("We need {0} 1 dollar.".format(Dollar1))
But i want to print only if that type of banknote is used. For example if total amount is 101 dollar than program prints
We need 2 50 dollar.
We need 0 20 dollar.
We need 0 10 dollar.
We need 0 5 dollar.
We need 1 1 dollar.
But i dont want to print the ones with 0 value. I only want it to print
We need 2 50 dollar.
We need 1 1 dollar.
This was an example of my struggle. I can not code this kind of loops or conditions. Thank you very much for any help.
Instead of writing an if statement for all of these just zip them together and use a for loop:
counts = [Dollar50, Dollar20, Dollar10, Dollar5, Dollar1]
ammounts = [50, 20, 10, 5, 1]
for i, j in zip(counts, ammounts):
if i:
print("We need {} {} dollar.".format(i, j))
All you need is an if condition.
As an exercise, you should try to write DRY code. Using loops and lists would look like this
face_values = [50, 20, 10, 5, 1]
amounts = [0]*5
remaining_money = int(input("Please enter the total amount: "))
# While you have money left, calculate the next most 'dollar_value' you can use
i = 0 # This is an index over the 'dollars' list
while remaining_money > 0:
d = face_values[i]
amounts[i] = remaining_money // d
remaining_money %= d
i+=1
denomination = "dollar bill"
denomination_plural = denomination + "s"
# Iterate both values and amounts together and print them
for val, amount in zip(face_values, amounts):
if amount == 1: # Filter out any non-positive amounts so you don't show them
print("We need {} {} {}.".format(val, amount, denomination))
else if amount > 1:
print("We need {} {} {}.".format(val, amount, denomination_plural))
Use
if Dollar50:
print("We need {0} 50 dollar.".format(Dollar50))
if the value is 0, it won't print anything.
Speaking simplistically, just add an if statement around each print statement checking for a 0.
if Dollar50 != 0:
print("We need {0} 50 dollar.".format(Dollar50))
if Dollar20 != 0:
print("We need {0} 20 dollar.".format(Dollar20))
Continue that for each item.

How can I get the average of a range of inputs?

I have to create a program that shows the arithmetic mean of a list of variables. There are supposed to be 50 grades.
I'm pretty much stuck. Right now I´ve only got:
for c in range (0,50):
grade = ("What is the grade?")
Also, how could I print the count of grades that are below 50?
Any help is appreciated.
If you don't mind using numpy this is ridiculously easy:
import numpy as np
print np.mean(grades)
Or if you'd rather not import anything,
print float(sum(grades))/len(grades)
To get the number of grades below 50, assuming you have them all in a list, you could do:
grades2 = [x for x in grades if x < 50]
print len(grades2)
Assuming you have a list with all the grades.
avg = sum(gradeList)/len(gradeList)
This is actually faster than numpy.mean().
To find the number of grades less than 50 you can put it in a loop with a conditional statement.
numPoorGrades = 0
for g in grades:
if g < 50:
numPoorGrades += 1
You could also write this a little more compactly using a list comprehension.
numPoorGrades = len([g for g in grades if g < 50])
First of all, assuming grades is a list containing the grades, you would want to iterate over the grades list, and not iterate over range(0,50).
Second, in every iteration you can use a variable to count how many grades you have seen so far, and another variable that sums all the grades so far. Something like that:
num_grades = 0
sum_grades = 0
for grade in grades:
num_grades += 1 # this is the same as writing num_grades = num_grades + 1
sum_grades += sum # same as writing sum_grades = sum_grades + sum
Now all you need to do is to divide sum_grades by num_grades to get the result.
average = float(sum_grade)s / max(num_grades,1)
I used the max function that returns the maximum number between num_grades and 1 - in case the list of grades is empty, num_grades will be 0 and division by 0 is undefined.
I used float to get a fraction.
To count the number of grades lower than 50, you can add another variable num_failed and initialize him to 0 just like num_counts, add an if that check if grade is lower than 50 and if so increase num_failed by 1.
Try the following. Function isNumber tries to convert the input, which is read as a string, to a float, which I believe convers the integer range too and is the floating-point type in Python 3, which is the version I'm using. The try...except block is similar in a way to the try...catch statement found in other programming languages.
#Checks whether the value is a valid number:
def isNumber( value ):
try:
float( value )
return True
except:
return False
#Variables initialization:
numberOfGradesBelow50 = 0
sumOfAllGrades = 0
#Input:
for c in range( 0, 5 ):
currentGradeAsString = input( "What is the grade? " )
while not isNumber( currentGradeAsString ):
currentGradeAsString = input( "Invalid value. What is the grade? " )
currentGradeAsFloat = float( currentGradeAsString )
sumOfAllGrades += currentGradeAsFloat
if currentGradeAsFloat < 50.0:
numberOfGradesBelow50 += 1
#Displays results:
print( "The average is " + str( sumOfAllGrades / 5 ) + "." )
print( "You entered " + str( numberOfGradesBelow50 ) + " grades below 50." )

Categories

Resources