saving last results in a text file - python

the problem i have is that i have a quiz which the user can pick from 3 classes. they then proceed to complete the quiz and currently their name and score is saved into a text file for the correct class (there are 3 different files for the 3 different classes). but how do i make it so if the same user has completed the quiz that only the last 2 scores that the student obtained is saved in the file rather than all of the scores.
if classChoice ==1:
File=open("A.txt","a+")
File.write(names+","+str(score)+"\n")
File.close()
if classChoice ==2:
File=open("B.txt","a+")
File.write(names+","+str(score)+"\n")
File.close()
if classChoice ==3:
File=open("C.txt","a+")
File.write(names+","+str(score)+"\n")
File.close()

Clearly you want to save your data in a specific data structure defined by yours. In your case you are interested in saving only last two scores of a specific student.
Let's observe how does your file "A.txt" look:
John,90
Sam,80
Alice,100
Sam,90
John,100
Instead of appending text each time, you have to read the whole file first, and convert it to something you can work with like dictionary.
def convert_file_to_dict(path):
d = {}
lines = open(path).splitlines()
for line in lines:
name, grade = line.split(',')
if name in d:
d[name].append(grade)
else:
d[name] = [grade]
return grade
In our case if I'll call convert_file_to_dict('A.txt'), I will receive dictionary which consists of { 'John':['90','100'], 'Sam':['80','90'], 'Alice':['100'] }. Notice that the order in the list of grades is preserved by order of lines in "A.txt".
Now with that dictionary you can control that only last 2 grades are kept:
def insert_new_grade(grades_dict, name, grade):
if name in grades_dict:
if len(grades_dict[name]) == 1:
grades_dict[name].append(str(grade))
else:
grades_dict[name] = grades_dict[name][1:] + [str(grade)]
else:
grades_dict[name] = [str(grade)]
Now all you need is to write a function which converts this dict to a file...
* You might want to use helpful objects like collections.defaultdict, but I didn't want to overkill here...

Related

Error is being shown when I run the code and I am unable to figure out the second question

import pickle
med = {}
medfile = open("Medicines.dat","wb")
while True:
name = input("Enter the name: ")
company = input("Enter the company: ")
chemical = input("Enter the chemical: ")
price = input("Enter the price: ")
med['name'] = name
med['company'] = company
med['chemical'] = chemical
med['price'] = price
pickle.dump(med,medfile)
ans = input("Wouldyou like to add more(y/n) ")
if ans == "y":
continue
elif ans == "n":
break
medfile = open("Medicines.dat","r+")
print(pickle.load(medfile))
medfile.close()
The question is as follows:
A binary file "Medicines.dat has structure [Name, Company, Chemical, Price] a) Write a user defined function add_data() to input the data for a record and store in the file b) Write a function search() which accepts a company name and displays the details of all the Medicines by that company
There are a few problems here:
1st Opening the file correctly
medfile = open("Medicines.dat","r+")
You mean rb. The difference is explained here, but pickle parsing requires the file to be in "binary" mode, hence the "b".
2nd Closing the file correctly
You should close the file before re-opening it for writing, as a matter of best practce. (medfile.close()). Even better, python will take care of when the file gets closed if you use the "with" syntax to create a context
3rd Having the right values
While the code should now run, I doubt it will do what you want. Your query asks "Wouldyou [sic] like to add more(y/n)", but it does not look to me like it is adding more values, since you use the same "med" dictionary over and over. Consider how the "new" fields would ever be distinguishable from the "old" ones, based on their key

How to add a string and integer into a file and then sort it?

In my code the program asks for the users name and score. However I can send the score to a file and sort it. Is there any way to change the code so that the player name gets sent to the file and also sorts along with its corresponding number.
player_1=input('What is your name?')
points1=input('What is your score?')
player_2=input('What is your name?')
points2=input('What is your score?')
leaderboard=input('Type YES if you would like to see the tp scores and NO if you wouldnt')
while leaderboard=='YES':
Scorefile=open('scores.txt','a')
Scorefile.write(points1)
Scorefile.write("\n")
Scorefile.write(points2)
Scorefile.write("\n")
Scorefile.close()
Scorefile = open('scores.txt','r')
with open('scores.txt','r') as Scorefile:
scores=Scorefile.readline()
List1=[]
while scores:
scores2=(scores.strip())
List1.append(scores2)
scores=Scorefile.readline()
for i in range(0, len(List1)):
List1[i] = int(List1[i])
List1.sort(reverse=True)
print(List1[0:5])
leaderboard='ANYTHING'
while leaderboard=='NO':
sys.exit()
Why not create 2 files and have the 1st file store strings and 2nd file store ints.
Then extract the info if needed from both. Very simple and easy.

Which file mode to choose and creating lists in a loop

back again with another problem. I am trying to make a "table maker" - for now just creating files with dictionaries and checking keys.
I have two problems: firstly i don't know if there is a file format for writing in binary but not overwriting a previous file if it already exists? I tried the (try, except) method but the excepted FileExistsError does never come up :/ (in the createTable function)
Secondly I have a problem with creating lists. I made a loop which asks for entries and values for them to be stored in separate lists. Those lists will later be zipped into a dictionary and pickled into a file. (in the createTable function)
Of course if there are other mistakes I'd love them pointed out :)
import pickle
def checkTable(nameOfTable) :
try :
#seeing what is it they are looking for
prompt = input("What do you want to check?\n")
with open("%s.pkl" % nameOfTable, "rb") as f:
data = pickle.load(f)
#getting what they want from the data from table
whatTheyWant = data.get(prompt, "There is nothing like that in the table.\n")
print(whatTheyWant)
#if table doesn't exist
except IOError as e:
print("Sorry such a directory doesn't exist.\n")
def createTable(nameOfYourTable) :
try :
#opens a new file with the table
with open("%s.pkl" %nameOfYourTable, "wb+") as f :
decision = "yes"
if decision == "yes" :
#asking for entries and keys to put into the table
#creates lists with entries and values to be zipped together
entry.append = input("What is the entry?\n")
value.append = input("What is the value of the entry?\n")
decision = input("Do you want to go on? (yes/no)\n")
i += 1
else :
#getting it all into a dictionary and putting it into a file
table={dict(zip(entry, value))}
pickle.dump(table, f)
#if a file with the name already exists
except FileExistsError as e :
print("Sorry, a file with this name already exists.")
#what the person wants to do
answer = input("Hello. Do you want to create a table or check an existing one?\n")
#asking for the name of the new table
if answer == "create" :
nameOfYourTable = input("What do you want the table to be called?\n")
createTable(nameOfYourTable)
#asking what table to look in
elif answer == "check" :
nameOfTable = input("What is the name of the table?\n")
checkTable(nameOfTable)
else :
print("\nThat's not a valid option.\n")
print("Thank you for using me. It was very nice.")
There is a file mode just for what you want, open(file, "x"), add b or t as per your need.
In x mode a file is created only when it does not already exist, raises exception otherwise. The createTable function does not really make sense to me. decision = "yes" then if decision == "yes":? decision is supposed to be a global? It's very fuzzy.
You need to pickle read the list from the file first, add to the list, and then write a new pickle file at the end. Btw, you can check if a file exists with os.path.exists. Appending items to a list is done with list_name.append(new_item). You need to have initialized the list first with list_name = [].

How to unpickle objects from .pkl file using python

I created a student class.I stored every student details in a file.I used serialization concept to store the details.The problem is while unpickling the data it gives first object only.Can anyone say how to retrieve all objects which are in .pkl file
and my code is
this is my code
'''
Created on Apr 20, 2015
#author: murali
'''
import pickle
from pip._vendor.distlib.compat import raw_input
class Student:
def __init__(self, name, roll, sex, subject, total):
"""Return a new Car object."""
self.name = name
self.roll = roll
self.sex = sex
self.subject = subject
self.total = total
print ("*************MENU*******************************")
print ("\t 1.Add New Student")
print ("\t 2.Display all Students")
print ("\t 3.Delete Student")
print ("\t 4.Display all Boys")
print ("\t 5.Display all Girls")
print ("\t 6.Display ascending order of marks")
print ("\t 7.Display alphabetical order of names ")
print ("\t 0.exit")
print ("************************************************")
print ("\n Enter your choice")
ch=int(raw_input())
if ch==1:
print ("Enter Student Details")
print ("Enter Student Name")
n=raw_input()
print ("Enter Student Roll number")
r=raw_input()
print ("Male or Female")
s=raw_input()
print ("Enter Subject ")
su=raw_input()
print ("Enter Student marks ")
t=raw_input()
s=Student(n,r,s,su,t);
with open("save2.pkl",'ab') as outfile:
pickle.dump(s,outfile)
print ("Data saved Successfully")
elif ch==2:
st=[];
f=open("save2.pkl",'rb')
storedlist=pickle.load(f)
print (storedlist)
#st.append(storedlist)
print ("Students are-")
print (storedlist)
#for i in storedlist:
print(storedlist.name)
print(storedlist.roll)
print(storedlist.sex)
print(storedlist.subject)
print(storedlist.total)
f.close();
#s1=None
#with open("save2.pkl",'rb') as infile:
#s1=pickle.load(infile)
#print (s1.name)
#print (s1.roll)
#print (s1.sex)
#print (s1.subject)
The issue you're encountering is that pickle.load only reads one item from your pkl file. That's just how its designed. If you have more than one item in the same file, you'll need to repeatedly load them until you get an EOFError when there is nothing more to read. Something like:
students = []
try:
with open("save2.pkl",'rb') as f:
while True: # loop indefinitely
students.append(pickle.load(f)) # add each item from the file to a list
except EOFError: # the exception is used to break the loop
pass # we don't need to do anything special
Alternatively, you could maintain in memory a complete list of the items your file is intended to contain (e.g. all the Student instances). When the list is modified, you'd pickle the whole list and write it all out together in one call to pickle.dump, overwriting the previous contents of the your data file. Rather than reading the data when the user requested it, you'd read it at the start of the program, and already have it in memory if the user wants it later.
This is a bit harder to show, as I don't want to rewrite large chunks of your code. I think these snippets are all you need:
Just below definition of the Student class:
try:
with open("save2.pkl",'rb') as f:
students = pickle.load(f) # just one call, loads the whole list
except FileNotFoundError: # if the file doesn't exist, make an empty list
students = []
Where you are currently appending to the file:
s=Student(n,r,s,su,t)
students.append(s) # update the in-memory list of students
with open("save2.pkl",'wb') as outfile: # use mode "w" to overwrite existing file
pickle.dump(students, outfile) # dump the whole list, not only s
print ("Data saved Successfully")
In the later code you wouldn't need to re-read the file. It can just use the students list you already have in memory.
This second approach is not terribly useful given your current menu design which can only be passed through a single time. But if you later put the menu in a loop (as the 0 option suggests you eventually will want to do), you might appreciate not needing to read the data file over and over.
This approach is also much better than the other version if you ever extend your Student type to have references to other Student instances (perhaps you're recording lab partners, or teams for some group project). If you pickle such interconnected objects separately, the links between them will not be retained when you load them again. The loaded versions will still have references, but the references will be to copies of the other Student instances, not the same ones you'll get when the other Students are loaded themselves. If you dump and load a whole list of Students at once, however, their interconnections will be maintained. (This is fairly deep stuff, don't worry too much if you don't understand what I'm talking about.)

'Splitting' List into several Arrays

I'm trying to complete a Project that will show total annual sales from an specific list contained in a .txt file.
The list is formatted this way:
-lastname, firstname (string)
-45.7 (float)
-456.4 (float)
-345.5 (float)
-lastname2, firstname2 (string)
-3354.7 (float)
-54.6 (float)
-56.2 (float)
-lastname3, firstname3 (string)
-76.6 (float)
-34.2 (float)
-48.2 (float)
And so on.... Actually, 7 different "employees" followed by 12 set of "numbers" (months of the year)....but that example should suffice to give an idea of what I'm trying to do.
I need to output this specific information of every "employee"
-Name of employee
-Total Sum (sum of the 12 numbers in the list)
So my logic is taking me to this conclusion, but I don't know where to start:
Create 7 different arrays to store each "employee" data.
With this logic, I need to split the main list into independent arrays so I can work with them.
How can this be achieved? And also, if I don't have a predefined number of employees (but a defined format :: "Name" followed by 12 months of numbers)...how can I achieve this?
I'm sure I can figure once I get an idea how to "split" a list in different sections -- Every 13 lines?
Yes, at every thirteenth line you'd have the information of an employee.
However, instead of using twelve different lists, you can use a dictionary of lists, so that you wouldn't have to worry about the number of employees.
And you can either use a parameter on the number of lines directed to each employee.
You could do the following:
infile = open("file.txt", "rt")
employee = dict()
name = infile.readline().strip()
while name:
employee[name] = list()
for i in xrange(1, 12):
val = float(infile.readline().strip())
employee[name].append(val)
name = infile.readline().strip()
Some ways to access dictionary entries:
for name, months in employee.items():
print name
print months
for name in employee.keys():
print name
print employee[name]
for months in employee.values():
print months
for name, months in (employee.keys(), employee.values()):
print name
print months
The entire process goes as follows:
infile = open("file.txt", "rt")
employee = dict()
name = infile.readline().strip()
while name:
val = 0.0
for i in xrange(1, 12):
val += float(infile.readline().strip())
employee[name] = val
print ">>> Employee:", name, " -- salary:", str(employee[name])
name = infile.readline().strip()
Sorry for being round the bush, somehow (:
Here is option.
Not good, but still brute option.
summed = 0
with open("file.txt", "rt") as f:
print f.readline() # We print first line (first man)
for line in f:
# then we suppose every line is float.
try:
# convert to float
value = float(line.strip())
# add to sum
summed += value
# If it does not convert, then it is next person
except ValueError:
# print sum for previous person
print summed
# print new name
print line
# reset sum
summed = 0
# on end of file there is no errors, so we print lst result
print summed
since you need more flexibility, there is another option:
data = {} # dict: list of all values for person by person name
with open("file.txt", "rt") as f:
data_key = f.readline() # We remember first line (first man)
data[data_key] = [] # empty list of values
for line in f:
# then we suppose every line is float.
try:
# convert to float
value = float(line.strip())
# add to data
data[data_key].append(value)
# If it does not convert, then it is next person
except ValueError:
# next person's name
data_key = line
# new list
data[data_key] = []
Q: let's say that I want to print a '2% bonus' to employees that made more than 7000 in total sales (12 months)
for employee, stats in data.iteritems():
if sum(stats) > 7000:
print employee + " done 7000 in total sales! need 2% bonus"
I would not create 7 different arrays. I would create some sort of data structure to hold all the relevant information for one employee in one data type (this is python, but surely you can create data structures in python as well).
Then, as you process the data for each employee, all you have to do is iterate over one array of employee data elements. That way, it's much easier to keep track of the indices of the data (or maybe even eliminates the need to!).
This is especially helpful if you want to sort the data somehow. That way, you'd only have to sort one array instead of 7.

Categories