Read and write to a list of names and scores - python - python

I am trying to create a program that gives the user a short quiz and create a score, which I have done, then I would like to add them to a list in a .txt file. In the program I will ask them their name, so say I have a list such as this;
Bob,7
Bill,5
Jane,6
and someone takes the quiz and inputs the name Bob and gets a score 4 the list will update to;
Bob,4
Bill,5
Jane,6
or someone new takes a quiz, Sarah it will change to;
Bob,4
Bill,5
Jane,6
Sarah,7
So far I have;
import random
file = open("scores.txt", "r")
UserScore=random.randint(0,10)
lines = file.readlines()
file.close()
student=input('What is your name? ')
file = open("scores.txt", "w")
for line in lines:
line = line.strip()
name, score = line.strip().split(",")
if name!=student:
file.write(line)
else:
file.write(name +',' +str(UserScore))
I've randomised the score for now to make it easier to read, however that will be from what the user answered correctly, and I thought this code would read the file then check each name from each line and if the name they entered is the same to the name in the list the line will be replaced with the name and score. However, the file just ends up blank, what am I doing wrong?

Here is what I think is a better idea using the Python pickle module:
In [1]: import pickle
In [2]: scores={'Bob':75, 'Angie':60, 'Anita':80} #create a dict called scores
In [3]: pickle.dump(scores,open('scores.dat','wb')) #dump the pickled object into the file
In [4]: !ls scores.dat #verify that the file has been created
scores.dat
In [5]: !cat scores.dat #list out the file
(dp0
S'Bob'
p1
I75
sS'Angie'
p2
I60
sS'Anita'
p3
I80
s.
In [9]: tscores = pickle.load(open('scores.dat','rb')) #Verification: load the pickled object from the file into a new dict
In [10]: tscores #Verification: list out the new dict
Out[10]: {'Angie': 60, 'Anita': 80, 'Bob': 75}
In [11]: scores == tscores #Verify that the dict object is equivalent to the newly created dict object
Out[11]: True

I tried your code and the first time you run it, then you rewrite the file in one single line. So the next time you run the script on this single line file, you get an unpack exception in the split function and hence you write nothing to the file, resulting in an empty file.
A solution could be to add the newline char again when writing the lines to the file.
import random
file = open("scores.txt", "r")
UserScore=random.randint(0,10)
lines = file.readlines()
file.close()
student=input('What is your name? ')
file = open("scores.txt", "w")
for line in lines:
line = line.strip()
name, score = line.strip().split(",")
if name!=student:
file.write(line + '\n')
else:
file.write(name +',' +str(UserScore) + '\n')

This should do what you want
import random
file = open("scores.txt", "r")
UserScore=random.randint(0,10)
lines = file.readlines()
file.close()
student=input('What is your name? ')
flag = True
file = open("scores.txt", "w")
for line in lines:
line = line.strip()
name, score = line.strip().split(",")
if name!=student:
file.write(line + '\n')
else:
file.write(name +',' +str(UserScore) + '\n')
flag = False
if flag:
file.write(student +',' +str(UserScore) + '\n')

I adjusted a bit of your code and took the liberty to remove the random part and name, score part. But I got some working code. I assume you can make it work for your situation.
file = open("scores.txt", "r+")
lines = file.readlines()
file.close()
us = 15
student = input('What is your name? ')
ls = []
file = open("scores.txt", "r+")
found_student = False
for line in lines:
line = line.strip()
ls = line.split(",")
print("Parsing: " + str(ls))
if not line:
print("Empty line")
pass
elif ls[0] != student:
file.write(line + "\n")
else:
found_student = True
file.write(ls[0] + ',' + str(us) + "\n")
if not found_student:
file.write(student + ',' + str(us) + "\n" )
file.close()

Related

IndexError: list index out of range - PythonError

I'm creating a program that should create a file (.txt) based on each line of 'clouds.txt'. This is my code:
def CreateFile():
global file_name
f = open(file_name,"w+")
f.write(list_email + ":")
f.close()
def WriteInConfig():
f = open("config/config.txt","a")
f.write(list_name + "\n")
f.close()
with open("clouds.txt","r") as f:
list_lines = sum(1 for line in open('clouds.txt'))
lines = f.readline()
for line in lines:
first_line = f.readline().strip()
list_email = first_line.split('|')[1] #email
print("Email: " + list_email)
list_pass = first_line.split('|')[2] #pass
print("Pass: " + list_pass)
list_name = first_line.split('|')[3] #name
print(list_name)
global file_name
file_name = "config/." + list_name + ".txt"
with open('clouds.txt', 'r') as fin:
data = fin.read().splitlines(True)
with open('clouds.txt', 'w') as fout:
fout.writelines(data[1:])
CreateFile()
WriteInConfig()
The clouds.txt file looks like this:
>|clouds.n1c0+mega01#gmail.com|cwSHklDIybllCD1OD4M|Mega01|15|39.91|FdUkLiW0ThDeDkSlqRThMQ| |x
|clouds.n1c0+mega02#gmail.com|tNFVlux4ALC|Mega02|50|49.05|lq1cTyp13Bh9-hc6cZp1RQ|xxx|x
|clouds.n1c0+mega03#gmail.com|7fe4196A4CUT3V|Mega03|50|49.94|BzW7NOGmfhQ01cy9dAdlmg|xxx|xxx >
Everything works fine until 'Mega48'. There I get "IndexError: list index out of range"
>|clouds.n1c0+mega47#gmail.com|bd61t9zxcuC1Yx|Mega47|50|10|Xjff6C8mzEqpa3VcaalUuA|xxx|x
|clouds.n1c0+mega48#gmail.com|kBdnyB6i0PUyUb|Mega48|50|0|R6YfuGP2hvE-uds0ylbQtQ|xxx|x
|clouds.n1c0+mega49#gmail.com|OcAdgpS4tmSLTO|Mega49|50|28.65|xxx| >
I checked and there are no spaces/other characters. As you could see, after creating the file, the program deletes the line. After the error, if I'm starting the program again (and starts from 'Mega47') it doesn't show the error, and everything works as planned.
Any ideas how to fix this?
I see many mistakes in your code. First, what do you want with this list_lines = sum(1 for line in open('clouds.txt'))?
You have a problem in your for loop because you did lines = f.readline() so lines is the first line, then you do for line in lines where line will be each character of the first line and there are more character in the first line than lines in your file to read.
[edited]
you don't need to know the number of lines in the file to do a for loop. You can just do for line in f:, then you don't need to read the line again with readline it is already in the variable line

Why doesn't this writing to file in python work?

The idea behind the following code is that the if the variable crop is already contained within the .txt file the variable quantity will be added on to the end of the same line as crop. This is my attempt at doing this, however it doesn't work: you really need to run it to understand, but, essentially, the wrong section of the list is added to, an ever expanding series of '/' appear and the line breaks disappear. Does anyone know how to modify this code so it functions properly?
What should be outputted:
Lettuce 77 88 100
Tomato 99
What actually is outputted:
["['\\n', 'Lettuce 77 \\n88 ', 'Tomato 88 ']100 "]
Code:
def appendA ():
with open('alpha.txt', 'r') as file_1:
lines = file_1.readlines()
for line in lines:
if crop in line:
index = lines.index(line)
line = str(line + quantity + ' ')
lines [index] = line
newlines = str(lines)
#The idea here is that the variable quantity is added onto the end
# of the same row as the entered crop in the .txt file.
with open('alpha.txt', 'w') as file_3:
file_3.write (newlines)
def appendB ():
with open('alpha.txt', 'a') as file_2:
file_2.write ('\n')
file_2.write (crop + ' ')
file_2.write (quantity + ' ')
crop = input("Which crop? ")
quantity = input("How many? ")
with open('alpha.txt', 'a') as file_0:
if crop in open('alpha.txt').read():
appendA ()
else:
appendB ()
Let's start! Your code should look something like this:
def appendA():
with open('alpha.txt', 'r') as file_1:
lines = []
for line in file_1:
if crop in line:
line = str(line.rstrip("\n") + quantity + "\n")
lines.append(line)
#The idea here is that the variable quantity is added onto the end
# of the same row as the entered crop in the .txt file.
with open('alpha.txt', 'w') as file_3:
file_3.writelines(lines)
def appendB():
with open('alpha.txt', 'a') as file_2:
file_2.write('\n')
file_2.write(crop + ' ')
file_2.write(quantity + ' ')
crop = "Whichcrop"
quantity = "+!!!+"
with open('alpha.txt') as file_0:
if crop in file_0.read():
print("appendA")
appendA()
else:
print("appendB")
appendB()
with open('alpha.txt', 'a') as file_0:
if crop in open('alpha.txt').read():
appendA ()
else:
appendB ()
Also you make several mistakes.
This line "with open('alpha.txt', 'a') as file_0:" open file with context for append in the end of file, but you dont use variable file_0. I think it's extra.
On next step you opened file for check "crop in open('alpha.txt').read()", but never close it.
["['\n', 'Lettuce 77 \n88 ', 'Tomato 88 ']100 "]
You get such a output because, you use write instead of writelines:
with open('alpha.txt', 'w') as file_3:
file_3.write (newlines)
Also you write in the file after each iteration, better to form a list of strings and then write to file.
newlines = str(lines) # you convert all lines list to str - so you get default conversion
and also you should replace whole file if you want to write in the middle
And you can also get read of appendB, because you still check every line and your code anyway is not optimal in terms of performance :)
from os import remove, close
def appendA(filename, crop, quantity):
result = []
exists = False
with open(filename, 'r') as file_1:
lines = file_1.readlines()
for line in lines:
if not crop in line:
result.append(line)
else:
exists = True
result.append(line.strip('\n') + quantity + '\n')
if not exists:
with open(filename, 'a') as file_2:
file_2.write ('\n' + crop + ' ' + quantity + ' ')
else:
tmp_file = filename + '.tmp'
with open(tmp_file, 'w') as file_3:
file_3.write(result)
remove(filename)
move(tmp_file, filename)
"str(lines)": lines is list type, you can use ''.join(lines) to
convert it to a string.
"line in lines": "line" end with a "\n"
Code indent error: "line newlines = ''.join(lines)" and the follow
"if crop in lines" is mistake, if crop named "AA" and "AABB", the
new input "AA" with return true, the quantity will be appended to
all lines including "AA" ,not only the "AA" line.
def appendA():
with open('alpha.txt', 'r') as file_1:
lines = file_1.readlines()
for line in lines:
if crop in line:
index = lines.index(line)
line = str(line.replace("\n", "") + ' ' + quantity + '\n')
lines[index] = line
newlines = ''.join(lines)
# The idea here is that the variable quantity is added onto the end
# of the same row as the entered crop in the .txt file.
with open('alpha.txt', 'w') as file_3:
file_3.write(newlines)
def appendB():
with open('alpha.txt', 'a') as file_2:
file_2.write("\n")
file_2.write(crop + ' ')
file_2.write(quantity + ' ')
crop = input("Which crop? ")
quantity = input("How many? ")
with open('alpha.txt', 'a') as file_0:
if crop in open('alpha.txt').read():
appendA()
else:
appendB()

Why is this code just deleting the whole contents of the file?

I am making a code that checks if a certain user name is in a text file.
If it is, it stores the score. However, once it reaches more than 3 scores it deletes the oldest to maintain it at 3 scores.
Here is my code:
if userclass=="1":
filefordataclass1 = open("Class1scores.txt", "a"); #this opens/creates a new text file
filefordataclass1.write(str(username) + ":" + str(score))#this converts the
filefordataclass1.write("\n")
user_scores = {}
with open("Class1scores.txt", "r+")as file:
file.seek(0)
scores = file.readlines()
for line in scores:
name, scores = line.rstrip('\n').split(':',1)
if name not in user_scores:
user_scores[name] = deque(maxlen=3)
temp_q = user_scores[name]
temp_q.append(str(score))
user_scores[name] = temp_q
filehandle=open("Class1scores.txt", "w")
for key, values in user_scores.items():
filehandle.write(name + ',')
filehandle.write(','.join(list(values)) + '\n')
filehandle.close()# Initialize score list
filefordataclass1.close
If you can tell me what is wrong with the python code and how to fix it It would be much appreciated.
Don't chance your file multiple times. First read the contents, then add the new score, then write everything:
from collections import defaultdict, deque
if userclass=="1":
user_scores = defaultdict(lambda: deque(maxlen=3))
with open("Class1scores.txt", "r") as lines:
for line in lines:
name, scores = line.rstrip('\n').split(':',1)
user_scores[name].extend(scores.split(','))
user_scores[username].append(str(score))
with open("Class1scores.txt", "w") as output:
for key, values in user_scores.items():
filehandle.write('%s:%s\n' % (key, ','.join(list(values))))
Otherwise you are lost in searching for errors.
You should open the output file with "a" (append) instead of "w" (write).
no need to open the file again in write mode as you have already opened the file in read/write mode with r+.Use seek and truncate after storing the file data in variable. Code is as follows:
from collections import defaultdict, deque
userclass = "1"
if userclass=="1":
user_scores = defaultdict(lambda: deque(maxlen=3))
f = open("Class1scores.txt", "r+")
lines = f.readlines()
print lines
for line in lines:
name, scores = line.rstrip().split(':')
user_scores[name].extend(scores.split(','))
if len(user_scores) > 0:
f.seek(0)
f.truncate()
for key, values in user_scores.items():
f.write('%s:%s\n' % (key, ','.join(list(values))))
f.close()
hope this helps :)

Python: Storing data in a text file and appending particular/individual lines

This is a computer science project that I've been working on.
Test scores are saved in a text file against a students name. for example:
Rob 21
Terry 12
Mike 33
I can get the program to do this but I want it to read the lines of the text file and identify if the name is already in existence. If so, it should add the next score onto the end of the line. If Terry takes the test again the scores should then read:
Rob 21
Terry 12 23
Mike 33
This is the relevant piece of code. It starts after the test is complete and the user has input their name, class and received their score.
import fileinput
print("Well done " +name+ ", your score is "+ (str(score)))
entry = (name +" "+ (str(score)))
if classchoice == "A":
classfile = open("classa.txt")
for line in classfile:
if name in line:
oldline = line
newline = (oldline+" "+(str(score)))
print (newline)
classfile.close()
else:
classfile = open("classb.txt","a")
classfile.write(entry)
classfile.write('\n')
classfile.close()
for line in fileinput.input("classa.txt", inplace=1):
line = line.replace(oldline,newline)
line = line.strip()
I'm having difficulty with this because:
The first part where it reads the lines in the files and finds the student name and results works but when I try to put the line together with the new score it ends up putting the new score underneath when it print (newline) so it looks like:
Terry 12
23
another issue is the else doesn't work. I get: local variable 'oldline' referenced before assignment
Could anyone help me with this. I'm new to python and this is a little overwhelming at the moment.
This is because when you read the file , and you get each line, it already has the newline (\n) at the end, so when you do -
newline = (oldline+" "+(str(score)))
oldline already has \n at the end. And hence you get something like - Name oldscore\n newscoe , and hence it comes on a new line.
You would need to strip off the previous newline before create the newline, Example -
newline = (oldline.rstrip()+" "+(str(score)))
--
Also, what you are doing seems to be very inefficient, you can directly use fileinput.input() for your case -
if classchoice == "A":
write_flag = True
with fileinput.input("classa.txt", inplace=1) as f:
for line in f:
line = line.rstrip()
if name in line:
line = line + " " + str(score)
write_flag = False
print(line)
#This is if `name` was never found, meaning we have to add the name to the file with the score.
if write_flag:
with open("classa.txt",'a') as f:
f.write("{} {}\n".format(name,score))
As indicated in the comments, using in would result in wrong entries getting updated. A way to overcome that would be to split the line and compare the first entry in the split -
if classchoice == "A":
write_flag = True
with fileinput.input("classa.txt", inplace=1) as f:
for line in f:
line = line.rstrip()
words = line.split()
if name == words[0]:
line = line + " " + str(score)
write_flag = False
print(line)
#This is if `name` was never found, meaning we have to add the name to the file with the score.
if write_flag:
with open("classa.txt",'a') as f:
f.write("{} {}\n".format(name,score))
Your logic and any logic using in is flawed and can harm your existing data, to see why:
infile:
stephen 12
paula 10
new_name, new_score = "paul",20
"paul" in "paula 10" -> True
infile after:
stephen 12
paula 10 20
Where is paul and why does paula now have two scores? Because you are matching substrings not exact names.
You are also using the wrong structure to store the data, use a dict with json:
To create the dict initially from your file use:
import csv
import json
with open("in.txt") as f:
r = csv.reader(f, delimiter=" ")
dct = {row[0]: row[1:] for row in r}
Then dump it to the file:
with open("in.txt", "w") as out:
json.dump(dct, out)
When you want to add new data just json.load and access using the key to add data or adding a new key/value pairing if the name does not exist:
new_name, new_score = "Terry", 20
with open("in.txt") as f:
dct = json.load(f)
dct[new_name] = new_score if new_name not in dct else dct[new_name] + [new_score]
with open("in.txt", "w") as out:
json.dump(dct, out)
in.txt will contain your updated data:
{"Mike": ["33"], "Rob": ["21"], "Terry": ["12", 20]}
If you are going to use a regular file then the correct approach is to check the name not using in, you can use a tempfile and shutil.move t0 update the original file:
from tempfile import NamedTemporaryFile
import csv
new_name, new_score = "Terry", 20
with open("in.txt") as f, NamedTemporaryFile("w",dir=".", delete=False) as out:
r = csv.reader(f, delimiter=" ")
wr = csv.writer(out, delimiter=" ")
found = False
for row in r:
# actually check the name for an exact match
if row[0] == new_name:
wr.writerow(row + [new_score])
found = True
else:
wr.writerow(row)
# if name is new, found will still be False
if not found:
wr.writerow([new_name, new_score])
# replace original file with updated
move(out.name, "in.txt")
Which will output:
Rob 21
Terry 12 20
Mike 33
Terry 20

Read lines from a text file into variables

I have two different functions in my program, one writes an output to a txt file (function A) and the other one reads it and should use it as an input (function B).
Function A works just fine (although i'm always open to suggestions on how i could improve).
It looks like this:
def createFile():
fileName = raw_input("Filename: ")
fileNameExt = fileName + ".txt" #to make sure a .txt extension is used
line1 = "1.1.1"
line2 = int(input("Enter line 2: ")
line3 = int(input("Enter line 3: ")
file = (fileNameExt, "w+")
file.write("%s\n%s\n%s" % (line1, line2, line3))
file.close()
return
This appears to work fine and will create a file like
1.1.1
123
456
Now, function B should use that file as an input. This is how far i've gotten so far:
def loadFile():
loadFileName = raw_input("Filename: ")
loadFile = open(loadFileName, "r")
line1 = loadFile.read(5)
That's where i'm stuck, i know how to use this first 5 characters but i need line 2 and 3 as variables too.
f = open('file.txt')
lines = f.readlines()
f.close()
lines is what you want
Other option:
f = open( "file.txt", "r" )
lines = []
for line in f:
lines.append(line)
f.close()
More read:
https://docs.python.org/2/tutorial/inputoutput.html#reading-and-writing-files
from string import ascii_uppercase
my_data = dict(zip(ascii_uppercase,open("some_file_to_read.txt"))
print my_data["A"]
this will store them in a dictionary with lettters as keys ... if you really want to cram it into variables(note that in general this is a TERRIBLE idea) you can do
globals().update(my_data)
print A

Categories

Resources