Rearranging a file - python

I have a piece of code (seen below) which enables me to be able to ask pupils a series of random questions and then save their name and scores to a file. I combined the name and score into a single variable called info, with the name coming first then the score. I now need to sort this information in order of score. Is there a way for me to make the score go in front of the name temporarily in the entire file so that I can use the sorted function to get it to go from lowest to highest?
Any help would be greatly appreciated!!! Thank you.
import random
import time
Name=input("What is your name?")
Class=input("Are you in Class A, B or C?")
print("Welcome" ,Name, "to the Maths Quiz!!")
time.sleep(3)
QuestionNumber=0
Operations=["+","-","x"]
answer=0
score=0
while QuestionNumber < 10:
Num1=random.randint(1,12)
Num2=random.randint(1,12)
QuestionNumber=QuestionNumber+1
operation = random.choice(Operations)
print("What is", Num1 ,operation, Num2)
guess=int(input("What is the answer to this question?"))
if operation =="+":
answer=Num1+Num2
elif operation =="-":
answer=Num1-Num2
elif operation =="x":
answer=Num1*Num2
if guess==answer:
score=score+1
print ("Correct")
else:
print("Incorrect")
print("Well done You got", score, "Out of 10!!")
score=str((score))
Info= (Name + (" ") + score)
if Class=="A":
ClassA=open("Class A Results.txt","a")
ClassA.write(Info)
ClassA.write(" \n")
ClassA.close()
elif Class=="B":
ClassB=open("Class B Results.txt","a")
ClassB.write(Info)
ClassB.write(" \n")
ClassB.close()
elif Class=="C":
ClassC=open("Class C Results.txt","a")
ClassC.write(" \n")
ClassC.write(Info)
ClassC.close()
Viewscores=input("Do you want to see previous scores? Y/N")
if Viewscores=="Y":
Classresults=input("Which Class would you like to see the results of?")
else:
print ("Thank you for using the maths quiz, press enter to close the program in 10 seconds")
time.sleep(10)
closeprogram=input("Hit enter")
if Classresults=="A":
ClassA=open("Class A Results.txt","r")
Class=Class
alphabet=ClassA.readlines()
for line in sorted(alphabet):
print(line)
elif Classresults=="B":
ClassB=open("Class B Results.txt","r")
Class=ClassB
alphabet=ClassB.readlines()
for line in sorted(alphabet):
print(line)
elif Classresults=="C":
ClassC=open("Class C Results.txt","r")
Class=ClassC
alphabet=ClassC.readlines()
for line in sorted(alphabet):
print(line)
else:
print ("That is not valid")

sorted's key function can do this for you, but it's much nicer if you haven't combined them into a single string, but store tuples of the pairs instead. Using operator.itemgetter generalizes nicely. Instead of storing:
score = str(score)
Info = Name + " " + score
store:
Info = (Name, score) # Score remains a float
Then when you need to sort, do:
# Imports at top of file, not each sort
from operator import itemgetter
...
for name, score in sorted(myunorderedinfo, key=itemgetter(1, 0)):
In the code you provided, you're writing to a file and reading back (which would require reparsing), so you may want to look at the csv module to store the pairs with proper formatting (simple space separation is easy to mess up); you'd have to convert the inputs back to float in that case though, since csv.reader passes back lists of str, but that's relatively easy to do with a simple generator expression (left as an exercise).

As an aside, you could make your code much neater by removing all that duplicated code:
VALID_CLASS_NAMES = {"A", "B", "C"}
if Classresults not in VALID_CLASS_NAMES:
print("Invalid class results selection")
raise Exception("BOOM")
filename = "Class {} Results.txt".format(Classresults)
with open(filename, "r") as class_results_file:
alphabet=class_results_file.readlines()
for line in sorted(alphabet):
print(line)
Now if you ever add class "D" then you just need to add it to the set of valid class names.

Related

why is the return of the program not good?

I'm new to python and there's a video on Youtube that I watched. I do the exact same code as he but mine doesn't work and I don' understand why.
Here's the code:
MAX_LINES = 3
def deposit():
while True:
amount = input("What would you like to deposit? $")
if amount.isdigit():
amount = int(amount)
if amount > 0:
break
else:
print("Amount must be greater than 0. ")
else:
print("Please enter a number. ")
return amount
def get_number_of_lines():
while True:
lines = input("Enter the number of lines to bet on (1-" + str(MAX_LINES) + ")? ")
if lines.isdigit():
lines = int(lines)
if 1 <= lines <= MAX_LINES:
break
else:
print("Please enter a valid number of lines. ")
else:
print("Please enter a number. ")
return lines
There are 3 problems.
Unindent amount does not match previous indent. I have no idea what does that mean
"return" can be used only within a function. As far as I'm concerned I'm using it in the function, copied the first function then pasted it into the second function and somehow it doesn't work
"lines" is not defined. What dou you mean it's not defined, I define it in the first line of the function
https://www.youtube.com/watch?v=th4OBktqK1I
This video's code what I'm trying to do
I appreciate any help!
I just simply don't understand why it works in one and not the other
You have one space too much in front of while True in function get_number_of_lines().
Yes used in functions to return value
Because function don't get inside while loop (because of indent problem), lines is never defined, probably this was the problem.
So try fix indent and run again

Comparing raw input to an specific element in an array using Python

I have a little piece of code in Python where I'm trying to compare a user input to a specific element in an array. Here is the code:
movies = ["movie 1", "movie2", "movie3"];
answer = raw_input("What is your guess: ")
if answer == movies[1]
then print ("yes that is correct")
else:
print ("no that is incorrect")
I know the indentation above looks wrong becasue I typed it out in the text box and I'm new to this site as well as python.
I also know that I probably need to use some sort of conditional loop, maybe a while loop, but I'm having trouble finding where I can compare user input string value to a string value in my array. Any ideas how I might accomplish this?
Have fun with Python! I guess you are trying to make a loop which keeps receiving inputs from user to compare with the desired input until user types the correct input. If so, one way, it can be implemented as following (but think of adding a break condition, like input == "Bored" , to avoid infinite loop and hard stopping your code):
movies = ["movie 1", "movie2", "movie3"]
correctAnswer = movies[1]
is_notCorrect = True
while(is_notCorrect):
answer = raw_input("What is your guess: ")
if answer == correctAnswer:
print("Yes, that is correct")
is_notCorrect = False
else:
print("No, that is incorrect")
In the code above, when is_notCorrect turns into False. At next condition checking, it will break condition, and done with the loop.
Your code has some issues
movies = ["movie 1", "movie2", "movie3"]; # No need the semi-colon in Python
answer = raw_input("What is your guess: ")
# Need a colon here after if condition, new line, and indent.
#If you don't like the colon, you need to write a different way with one line of code Eg: <Do A> if <Condition happens> else <Do B>
if answer == movies[1]
then print ("yes that is correct") # No then in if-else statement in Python
else:
print ("no that is incorrect")

Specific example: Is it possible to aviod the use of a global variable?

I have the following program and the variable(dictionary) in question is player_info that stores player information (name and goals). In order to solve the error that results currently, I simply need to make player_info a global variable, but I was wondering if stackoverflow experts could suggest or discuss the possibility of alternate ways of solving this problem WITHOUT the use of global variables.
Code
#FOOTBALL COACH app
#The program allows a user to enter a number of players (their names and goals scored) and then search for a player, returning their average goals for the three matches
import sys
def main():
mainmenu()
def mainmenu():
print("=====WELCOME to the MAIN MENU=============")
print("""
1..........Add New Players & Goals
2..........Search by Players
3..........Quit
=========================================
""")
choice=int(input("Enter choice:"))
if choice==1:
addplayers()
elif choice==2:
searchplayer(player_info)
elif choice==3:
sys.exit()
else:
print("You must make a valid choice - 1, 2 or 3")
def addplayers():
player_info= {} #create a dictionary that stores the player name: player goals
num_players = int(input("Please enter number of players you wish to enter:"))
print ("You are entering %s players" %num_players)
player_data = ['Match 1 goals : ', 'Match 2 goals : ', 'Match 3 goals : ']
for i in range(0,num_players):
player_name = input("Enter Player Name :")
player_info[player_name] = {}
for entry in player_data:
player_info[player_name][entry] = int(input(entry)) #storing the marks entered as integers to perform arithmetic operations later on.
mainmenu()
def searchplayer():
print("===============SEARCH by player: Calculate average goals==================")
name = input("Player name : ")
if name in player_info.keys():
#print student_info
print ("Average player goals : ", str(sum(player_info[name].values())/3.0))
else:
print("Please enter a valid player name:")
main()
As mentioned, I am aware that re-writing this in the addplayer() sub would fix the problem:
global player_info
player_info = {} #create a dictionary that stores the player name: player goals
...I am looking for ways to solve the problem WITHOUT the use of global variables.
Update:
One answer below using return player_info is what I would like to go with, but it doesn't quite work yet. Also, I need to return to the main menu each time a player is added, not quite sure how to do this, without a mainmenu call each time. Any suggestions? https://repl.it/JRl5/1
You can use return inside your function to avoid using global variables. A simple example is shown below:
def addplayers():
player_info= {}
name = input("Enter Name: ")
test = int(input("Enter a number: "))
player_info[name] = test
return player_info
player_info = addplayers()
If you then wanted to use this in another function you would just pass in the dictionary as an argument to that function:
def searchplayers(player_info):
print (player_info)
Note: An interesting answer on "Why are global variables evil?"
Edit:
Your addplayers() was calling mainmenu() which itself was being calling within mainmenu(). This is a recursive function and it might be best to avoid these unless there's a good reason for having it. I would put the contents of mainmenu inside a while loop until some condition is met. The complete code is shown below (I have removed the main function as it wasn't really doing anything):
def mainmenu():
stop = False
while stop == False:
print("=====WELCOME to the MAIN MENU=============")
print("""
1..........Add New Players & Goals
2..........Search by Players
3..........Quit
=========================================
""")
choice=int(input("Enter choice:"))
if choice==1:
player_info = addplayers()
elif choice==2:
searchplayer(player_info)
elif choice==3:
print ("Exit the main menu")
stop = True
else:
print("You must make a valid choice - 1, 2 or 3")
def addplayers():
player_info= {} #create a dictionary that stores the player name: player goals
num_players = int(input("Please enter number of players you wish to enter:"))
print ("You are entering %s players" %num_players)
player_data = ['Match 1 goals : ', 'Match 2 goals : ', 'Match 3 goals : ']
for i in range(0,num_players):
player_name = input("Enter Player Name :")
player_info[player_name] = {}
for entry in player_data:
player_info[player_name][entry] = int(input(entry)) #storing the marks entered as integers to perform arithmetic operations later on.
return player_info
def searchplayer(player_info):
print("===============SEARCH by player: Calculate average goals==================")
name = input("Player name : ")
if name in player_info.keys():
#print student_info
print ("Average player goals : ", str(sum(player_info[name].values())/3.0))
else:
print("Please enter a valid player name:")
mainmenu()
Store everything related to the game in a data structure, for example a dictionary, and pass it along in all functions where it can be updated as needed. Write a function "newgame" that creates this structure and initialises it.
In a way, this is object-oriented programming without using Python's syntax for classes and objects. Probably, you will learn these later in your class / tutorial.
Firstly, it is always possible to avoid using global variables. Secondly, global variables are possibly a misnomer in Python; global stores the variable in the local globals, which is typically the local module. That avoids a large part of the problem languages like C have with globals, in that they collide; Python has a namespace per module. For a simple script, where there is only one context, that might be fine.
Another namespace you might use is that of a particular object, using a class. This might look like:
class Game:
def mainmenu(self,...):
self.addplayers()
def addplayers(self):
self.player_info = {}
With that sort of code, whoever instantiates Game can make multiple instances, each passed as self when used. This is in large part syntactic sugar for a similar form of mutable state passing:
def mainmenu():
state={}
addplayers(state)
def addplayers(state):
state['player_info'] = {}
For some forms of programming, immutable state is far preferable (in particular, multithreading where data is shared, or to keep a log where you can undo steps). That's done similarly but you make a new state for each call:
def mainmenu():
state = {}
state = addplayers(state)
def addplayers(oldstate):
newstate = oldstate.copy()
newstate['player_info'] = {}
return newstate
Python isn't designed for this and doesn't really have a mode to keep you from inadvertently modifying mutable types. Some types can be converted to similar types that are immutable, like frozenset or tuple.
One of the weirder hacks we can do is calling a Python function with a different set of globals than it normally has. This can be abused to take your existing functions, global statements and all, and have them use a different variable:
fakeglobals = mainmenu.__globals__.copy()
exec(addplayers.__code__, fakeglobals)
Your original code has calls back and forth between functions, though, and each of those will reset their globals per that __globals__ attribute.
Your code also implements a loop using tail recursion. This is not optimized in Python and will run out of stack space eventually. In languages where tail recursion is optimized, you can pass along state as arguments continously and need not return it.

working out the mean from a csvfile already containing names

import operator
import csv
question= input("Are you a student or teacher: ")
if question=="student" or "s" or "Student":
print("You are using the wrong program. Please use the arithmetic quiz")
elif question=="teacher" or "t" or "Teacher":
print("Hello and welcome to the program which lets you see your students' scores in the arithmetic quizes")
form=input("What form do you want to view the results of? 1,2 or 3?")
if form=="1":
print("if you want the data sorted by names in alphabetical order")
print("enter 1, if you want the data sorted by scores highest to")
print("lowest enter 2, if you want the data sorted by average score")
teachermenu=input("highest to lowest enter 3:")
if teachermenu=="1":
start=csv.reader(open("form1.csv"), delimiter=";")
datasorted= sorted(start, key=operator.itemgetter(0))
data= open("form1.csv","r")
for eachline in datasorted:
eachline.sort()
print(eachline)
data.close()
elif teachermenu=="2":
data= open("form1.csv")
start=csv.reader(data)
for line in start:
scores = (line[1:5])
scores.sort(reverse = True)
print(scores)
elif teachermenu=="3":
studentsaverages=[]
data= open("form1.csv")
start=csv.reader(data)
for line in data:
numbers=(line[2:4])
numbers=list(map(int, numbers))
mean= round(sum(numbers)/len(numbers))
data.append(mean)
data.sort(reverse=True)
print(studentsaverages)
in this code the working out of the mean doesnt work and i dont know why
i have tried several times
but it doesnt seem to work
also the other parts of the code work
but the working out of the mean doesnt
e.g. putting it highest to lowest works
and so does putting the names in alphabetical order
If I understand correct what you are trying to do, you need to append and then sort the mean to the studentsaverages variable(after the for loop) instead of data.
for example:
elif teachermenu=="3":
studentsaverages=[]
data = open("form1.csv")
start=csv.reader(data)
for line in data:
numbers=(line[2:4])
numbers=list(map(int, numbers))
mean = round(sum(numbers)/len(numbers))
studentsaverages.append(mean)
studentsaverages.sort(reverse=True)
print(studentsaverages)

Inputting a number and outputting a name?

OK so I have this task at school, I'm a complete beginner but I have most of it down, I need to ask for the number and have it output the corresponding name (it's part "d") I managed to get part C to work but when I try to do the same thing to D it refuses to work. I know I'm probably doing something wrong but as I said I'm a complete beginner.
Also, can I tried changing my c+d to "if" so that I could add another "else" so that if the name/number that was input wasn't in any of the lists that it would return saying "invalid" but I cant seem to be able to change them to if statements.
Anyway here's the code I'm trying to make work, like I said, C works but D refuses to:
flag="F"
choice=""
#Looping-----------------------------------------------------------------------
while choice != "F" and choice !="f":
print( " A. Setup Name, Number and CallsPerDay \n"
" B. Display all names and numbers \n"
" C. Insert name to find out number \n"
" D. Insert number and find out name \n"
" E. Display Min, Max and Average CallsPerDay \n"
" F. Finish the Program")
choice=input("Select an option: \n\n")
#Selection---------------------------------------------------------------------
if choice=="A" or choice =="a":
if flag=="F":
names=["gordon", "david", "graeme", "joyce", "douglas", "brian", "suzanne", "karen"]
numb=[273429, 273666, 273512, 273999, 273123, 273224, 273324, 273424]
CPD=[30, 10, 15, 2, 5, 1, 3, 6]
length=len(numb)
print("Names, Numbers and CallsPerDay have now been set up \n")
flag="T"
elif flag=="T":
print("Lists already set up \n")
#---------------------------------------------------------------------------------
elif choice=="B" or choice=="b":
if flag=="F":
print('Run option A first!')
else:
for i in range(0,length,1):
print(names[i],numb[i], CPD[i], "\n")
#-------------------------------------------------------------------------------
elif choice=="C" or choice=="c":
if flag=="F":
print('Run option A first!')
else:
wanted=input('Name please ').lower()
i=0
while names[i] != wanted:
i=i+1
print('Number',numb[i])
#----------Part that refuses to work------------------------
elif choice=="D" or choice=="d":
if flag=="F":
print('Run option A first!')
else:
wanted=input('Number Please: ')
i=0
while numb[i] != wanted:
i=i+1
print('Number',names[i])
Here is the error I get in the shell when trying to do this:
A. Setup Name, Number and CallsPerDay
B. Display all names and numbers
C. Insert name to find out number
D. Insert number and find out name
E. Display Min, Max and Average CallsPerDay
F. Finish the Program
Select an option:
a
Names, Numbers and CallsPerDay have now been set up
A. Setup Name, Number and CallsPerDay
B. Display all names and numbers
C. Insert name to find out number
D. Insert number and find out name
E. Display Min, Max and Average CallsPerDay
F. Finish the Program
Select an option:
d
Number Please: 223666
Traceback (most recent call last):
File "G:\Lvl 5\sofware\menuNEWex - Copy.py", line 62, in <module>
while numb[i] != wanted:
IndexError: list index out of range
>>>
It should be outputting David, because they are both #2 on their lists
There's a few problems here. First, you need to convert wanted from a string to an integer so your comparison will work:
# Not this, because the return of input is a string
wanted=input('Number Please: ')
# But this. Note this will throw a ValueError if converting to an int fails!
wanted = int(input('Number please: '))
# This one has error handling!
try:
wanted = int(input('Number please: '))
except ValueError:
print("That's not a number")
Also, if your entered number is not in your list numb, your loop will still break when i becomes larger than the last index. Try using the index method instead, as it will either return the index of the number or throw a ValueError. Be careful though - that index is the first index of the element in the list. If the same number is repeated, you'll need another approach that handles conflicts:
try:
i = numb.index(wanted)
print('Number', names[i])
except ValueError:
print("No such number")
You should also consider wrapping your input requests in while loops that look for valid values. For example, you need a number for the above section:
i = None
while i is not None:
try:
i = int(input("Number: "))
except ValueError:
# i is still None
print("Must enter a number!")
An example running would give you this:
Number: a
Must enter a number!
Number: b
Must enter a number!
Number: 33
If you put checking your index in that loop, you get checking for integers and valid values at the same time.

Categories

Resources