text file reading and writing, ValueError: need more than 1 value to unpack - python-3.x

I need to make a program in a single def that opens a text file 'grades' where first, last and grade are separated by comas. Each line is a separate student. Then it displays students and grades as well as class average. Then goes on to add another student and grade and saves it to the text file while including the old students.
I guess I just don't understand the way python goes through the text file. If i comment out 'lines' I see it prints the old_names but its as if everything is gone after. When lines is not commented out 'old_names' is not printed which makes me think the file is closed? or empty? however everything is still in the txt file as it should be.
currently i get this error.... Which I am pretty sure is telling me I'm retarded there's no information in 'line'
File "D:\Dropbox\Dropbox\1Python\Batch Processinga\grades.py", line 45, in main
first_name[i], last_name[i], grades[i] = line.split(',')
ValueError: need more than 1 value to unpack
End goal is to get it to give me the current student names and grades, average. Then add one student, save that student and grade to file. Then be able to pull the file back up with all the students including the new one and do it all over again.
I apologize for being a nub.
def main():
#Declare variables
#List of strings: first_name, last_name
first_name = []
last_name = []
#List of floats: grades
grades = []
#Float grade_avg, new_grade
grade_avg = new_grade = 0.0
#string new_student
new_student = ''
#Intro
print("Program displays information from a text file to")
print("display student first name, last name, grade and")
print("class average then allows user to enter another")
print("student.\t")
#Open file “grades.txt” for reading
infile = open("grades.txt","r")
lines = infile.readlines()
old_names = infile.read()
print(old_names)
#Write for loop for each line creating a list
for i in len(lines):
#read in line
line = infile.readline()
#Split data
first_name[i], last_name[i], grades[i] = line.split(',')
#convert grades to floats
grades[i] = float(grades[i])
print(first_name, last_name, grades)
#close the file
infile.close()
#perform calculations for average
grade_avg = float(sum(grades)/len(grades))
#display results
print("Name\t\t Grade")
print("----------------------")
for n in range(5):
print(first_name[n], last_name[n], "\t", grades[n])
print('')
print('Average Grade:\t% 0.1f'%grade_avg)
#Prompt user for input of new student and grade
new_student = input('Please enter the First and Last name of new student:\n').title()
new_grade = eval(input("Please enter {}'s grade:".format(new_student)))
#Write new student and grade to grades.txt in same format as other records
new_student = new_student.split()
new_student = str(new_student[1] + ',' + new_student[0] + ',' + str(new_grade))
outfile = open("grades.txt","w")
print(old_names, new_student ,file=outfile)
outfile.close()enter code here

File objects in Python have a "file pointer", which keeps track of what data you've already read from the file. It uses this to know where to start looking when you call read or readline or readlines. Calling readlines moves the file pointer all the way to the end of the file; subsequent read calls will return an empty string. This explains why you're getting a ValueError on the line.split(',') line. line is an empty string, so line.split(",") returns a list of length 0, but you need a list of length 3 to do the triple assignment you're attempting.
Once you get the lines list, you don't need to interact with the infile object any more. You already have all the lines; you may as well simply iterate through them directly.
#Write for loop for each line creating a list
for line in lines:
columns = line.split(",")
first_name.append(columns[0])
last_name.append(columns[1])
grades.append(float(columns[2]))
Note that I'm using append instead of listName[i] = whatever. This is necessary because Python lists will not automatically resize themselves when you try to assign to an index that doesn't exist yet; you'll just get an IndexError. append, on the other hand, will resize the list as desired.

Related

How to get elements from a text file and searching them in another text file in python 3?

I have players.txt It is like:
Iteration: 1
Lloris
Kounde
Varane
Upamecano
Hernandez
Tchoumeni
Rabiot
Dembele
Griezman
Mbappe
Giroud
Iteration:2
Martinez
Molina
Otamendi
Romero
Tagliafico
Mac Allister
De Paul
Fernandez
Alvarez
Messi
Lautaro
Iteration 3:
xxxxx
yyyyy
zzzzz
namenamename
name
name
name
And I have superstarplayers.txt like:
Messi
Modric
Ronaldo
Mbappe
playername
playername
playername
playername
It goes like this, a lot of player name
No blank line in superstarplayer.txt
But in players.txt there is a blank line afterward the name of a player line. It is like 1st row is player 2nd row blank 3rd row is player 4th row is blank. One player one blank.
For each iteration, I want to get number of how many players in my iteration. And also I want to get the number of how many players is also exist in superstarplayers.txt
How can I do that in python3. I am learning python file operations.
(in players.txt in every iteration there are not always 11 players the numbers might different)
I'm learning how to read from a txt file, how to write to a txt file. I have no idea about how to get elements from a text file and searching them in another text file in python 3. How can I do that?
You can do what you are asking with this
def fix_data(lst):
""" Fixes any blank lines or empty strings"""
#remove the newline character from the strings if there
remove_newline = [x.replace("\n","") for x in lst]
#remove empty strings (your example has them) - also remove whitespace
remove_empty = [x.strip() for x in remove_newline]
#return data
return remove_empty
#open a text file for reading like this - its wrapped in a fix_data function
with open('/home/lewis/players.txt', 'r') as f:
lines = fix_data(f.readlines())
#open superstar players - also wrapped
with open('/home/lewis/superstar.txt', 'r') as f:
superstar_lines = fix_data(f.readlines())
#create a iteration dictionary.
iteration_store = {}
#create a variable to store the iteration no
iteration = 0
#create a variable to store the iteration start no
iteration_start = 0
#create a variable to store unknown player no
unknown_player = 1
#loop each line and and to dict on each iteration
for line in lines:
#check if an iteration line
iteration_start += 1
if "Iteration" in line:
# get the iteration number from the string by splitting the string on 'Iteration:' and taking the last value, then removing white space
iteration = line.split("Iteration:")[-1].strip()
#store this value in the dict as a list
iteration_store[iteration] = []
#set to zero
iteration_start = 0
# after the interation line is found then find the player name in every other space
elif iteration_start % 2 != 0:
#check if the player is unknown and rename the line
if line == "" or line is None:
#set the line
line = f"Unknown Player {unknown_player}"
#increment the player number
unknown_player += 1
#if not an iteration line then store the player name in the dict[list]
iteration_store[iteration].append(line)
#print the information
print(iteration_store)
#print a new line to seperate the data
print("\n\n")
#loop the newly create dict and print each iteration number and count of players
for k,v in iteration_store.items():
# check the superstar list for matches
superstars = [x for x in v if x in superstar_lines]
#print the information
print(f"Iteration: {k} - No Players {len(v)} - No Superstars {len(superstars)}")
EDIT:
Changed the code to take the player name from every other line after the "Iteration" line has been found. This will only work if it follows the following format ALWAYS
iteration line
player name (empty or not)
empty string
player name (empty or not)
ALSO
If the superstar player is not found, then there must be something that doesnt match like its written messi and Messi as they are different. The code is sound.
Read the codes, research and play with it. Google is your friend.

Find items in a text file that is a incantinated string of capitalized words that begin with a certain capital letter in python

I am trying to pull a string of input names that get saved to a text file. I need to pull them by capital letter which is input. I.E. the saved text file contains names DanielDanClark, and I need to pull the names that begin with D. I am stuck at this part
for i in range(num):
print("Name",i+1," >> Enter the name:")
n=input("")
names+=n
file=open("names.txt","w")
file.write(names)
lookUp=input("Did you want to look up any names?(Y/N)")
x= ord(lookUp)
if x == 110 or x == 78:
quit()
else:
letter=input("Enter the first letter of the names you want to look up in uppercase:")
file=open("names.txt","r")
fileNames=[]
file.list()
for letter in file:
fileNames.index(letter)
fileNames.close()
I know that the last 4 lines are probably way wrong. It is what I tried in my last failed attempt
Lets break down your code block by block
num = 5
names = ""
for i in range(num)
print("Name",i+1," >> Enter the name:")
n=input("")
names+=n
I took the liberty of giving num a value of 5, and names a value of "", just so the code will run. This block has no problems. And will create a string called names with all the input taken. You might consider putting a delimiter in, which makes it more easier to read back your data. A suggestion would be to use \n which is a line break, so when you get to writing the file, you actually have one name on each line, example:
num = 5
names = ""
for i in range(num)
print("Name",i+1," >> Enter the name:")
n = input()
names += n + "\n"
Now you are going to write the file:
file=open("names.txt","w")
file.write(names)
In this block you forget to close the file, and a better way is to fully specify the pathname of the file, example:
file = open(r"c:\somedir\somesubdir\names.txt","w")
file.write(names)
file.close()
or even better using with:
with open(r"c:\somedir\somesubdir\names.txt","w") as openfile:
openfile.write(names)
The following block you are asking if the user want to lookup a name, and then exit:
lookUp=input("Did you want to look up any names?(Y/N)")
x= ord(lookUp)
if x == 110 or x == 78:
quit()
First thing is that you are using quit() which should not be used in production code, see answers here you really should use sys.exit() which means you need to import the sys module. You then proceed to get the numeric value of the answer being either N or n and you check this in a if statement. You do not have to do ord() you can use a string comparisson directly in your if statement. Example:
lookup = input("Did you want to look up any names?(Y/N)")
if lookup.lower() == "n":
sys.exit()
Then you proceed to lookup the requested data, in the else: block of previous if statement:
else:
letter=input("Enter the first letter of the names you want to look up in uppercase:")
file=open("names.txt","r")
fileNames=[]
file.list()
for letter in file:
fileNames.index(letter)
fileNames.close()
This is not really working properly either, so this is where the delimiter \n is coming in handy. When a text file is opened, you can use a for line in file block to enumerate through the file line by line, and with \n delimiter added in your first block, each line is a name. You also go wrong in the for letter in file block, it does not do what you think it should be doing. It actually returns each letter in the file, regardless of whay you type in the input earlier. Here is a working example:
letter = input("Enter the first letter of the names you want to look up in uppercase:")
result = []
with open(r"c:\somedir\somesubdir\names.txt", "r") as openfile:
for line in openfile: ## loop thru the file line by line
line = line.strip('\n') ## get rid of the delimiter
if line[0].lower() == letter.lower(): ## compare the first (zero) character of the line
result.append(line) ## append to result
print(result) ## do something with the result
Putting it all together:
import sys
num = 5
names = ""
for i in range(num)
print("Name",i+1," >> Enter the name:")
n = input("")
names += n + "\n"
with open(r"c:\somedir\somesubdir\names.txt","w") as openfile:
openfile.write(names)
lookup = input("Did you want to look up any names?(Y/N)")
if lookup.lower() == "n":
sys.exit()
letter = input("Enter the first letter of the names you want to look up in uppercase:")
result = []
with open(r"c:\somedir\somesubdir\names.txt", "r") as openfile:
for line in openfile:
line = line.strip('\n')
if line[0].lower() == letter.lower():
result.append(line)
print(result)
One caveat I like to point out, when you create the file, you open the file in w mode, which will create a new file every time, therefore overwriting the a previous file. If you like to append to a file, you need to open it in a mode, which will append to an existing file, or create a new file when the file does not exist.

Why, when I sort a list of 13 numbers, does python only return the last number?

I have a list of first name, last name, and score in a text file that refers to a student and their test score. When I go to sort them so I can find the median score, it only returns from the sort() the last grade on the list. I need it to return all of them, but obviously sorted in order. Here is the part of my code in question:
def main():
#open file in read mode
gradeFile = open("grades.txt","r")
#read the column names and assign them to line1 variable
line1 = gradeFile.readline()
#tell it to look at lines 2 to the end
lines = gradeFile.readlines()
#seperate the list of lines into seperate lines
for line in lines:
#initialize grades list as an empty list
gradeList = []
#iterate through each line and take off the \n
line = line.rstrip()
line = line.split(",")
grades = line[-1]
try:
gradeList.append(float(grades))
except ValueError:
pass
#print(gradeList)
#sort the grades
gradeList.sort(reverse=False)
print(gradeList)
You clear the list each time the loop runs. Move the assignment outside the loop.

how would i go about reading a .txt file then ordering the data in descending order

ok so i would like it that when the user wants to check the high scores the output would print the data in descending order keep in mind that there are both names and numbers on the .txt file which is why im finding this so hard. If there is anything else you need please tell me in the
def highscore():
global line #sets global variable
for line in open('score.txt'):
print(line)
#=================================================================================
def new_highscores():
global name, f #sets global variables
if score >= 1:#if score is equal or more than 1 run code below
name = input('what is your name? ')
f = open ('score.txt', 'a') #opens score.txt file and put it into append mode
f.write (str(name)) #write name on .txt file
f.write (' - ') #write - on .txt file
f.write (str(score)) #write score on .txt file
f.write ('\n') #signifies end of line
f.close() #closes .txtfile
if score <= 0: #if score is equal to zero go back to menu 2
menu2()
I added this just in case there was a problem in the way i was writing on the file
The easiest thing to do is just maintain the high scores file in a sorted state. That way every time you want to print it out, just go ahead and do it. When you add a score, sort the list again. Here's a version of new_highscores that accomplishes just that:
def new_highscores():
""""Adds a global variable score to scores.txt after asking for name"""
# not sure you need name and f as global variables without seeing
# the rest of your code. This shouldn't hurt though
global name, f # sets global variables
if score >= 1: # if score is equal or more than 1 run code below
name = input('What is your name? ')
# here is where you do the part I was talking about:
# get the lines from the file
with open('score.txt') as f:
lines = f.readlines()
scores = []
for line in lines:
name_, score_ = line.split(' - ')
# turn score_ from a string to a number
score_ = float(score_)
# store score_ first so that we are sorting by score_ later
scores.append((score_, name_))
# add the data from the user
scores.append((score, name))
# sort the scores
scores.sort(reverse=True)
# erase the file
with open('score.txt', 'w') as f:
# write the new data
for score_, name_ in scores:
f.write('{} - {}\n'.format(name_, score_))
if score <= 0: # if score is equal to zero go back to menu 2
menu2()
You'll notice I'm using the with statement. You can learn more about that here, but essentially it works like this:
with open(filename) as file:
# do stuff with file
# file is **automatically** closed once you get down here.
Even if you leave the block for another reason (an Exception is thrown, you return from a function early, etc.) Using a with statement is a safer way to deal with files, because you're basically letting Python handle the closing of the file for you. And Python will never forget like a programmer will.
You can read more about split and format here and here
P.S., There is a method called binary search that would be more efficient, but I get the feeling you're just starting so I wanted to keep it simple. Essentially what you would do is search for the location in the file where the new score should be inserted by halving the search area at each point. Then when you write back to the file, only write the stuff that's different (from the new score onward.)

File input frequency sorting

so I have to write a program that:
Takes the filename as an argument.
Reads the file and counts, for each band, how many albums of that band are listed in the file. (http://vlm1.uta.edu/~cconly/teaching/cse1310_spring2015/assignments/assignment7/albums.txt)
Prints on the screen, in descending order of number of albums, a line for each band. Each line should contain the name of the band, followed by a colon and space, and then the number of albums for that band. This would look like this:
band1: number1
band2: number2
band3: number3
so there is my code below, but I keep getting tremendous errors that tells me that things aren't defined when they are, and I'll get this one as well --> TypeError: 'NoneType' object is not iterable, any help would be great!
import fileinput
import os
filename = open("albums.txt", "r") # open album.txt file
def process_line(line):
line = line.lower()
new_line = ""
for letter in line:
if letter in (""",.!"'()"""):
continue
elif letter == '-':
letter = ' '
new_line = new_line + letter
words = new_line.split()
return words
def count_words(filename):
if (os.path.isfile(filename) == False):
print("\nError: file " + filename + " does not exist.\n")
return
#in_file = open(filename, "r")
result = {}
for line in filename:
words = process_line(line)
for word in words:
if (word in result):
result[word] += 1
else:
result[word] = 1
def print_word_frequencies(dictionary):
print()
inverse = inverse_dictionary(dictionary)
frequencies = inverse.keys()
frequencies = list(frequencies) # convert frequencies to a list, so that we can sort it.
frequencies.sort() # sorting the list
frequencies.reverse() # reverse the sorting of the list
for frequency in frequencies: # for words with the same frequency, we want them sorted in
list_of_words = inverse[frequency]
list_of_words.sort() # sorting in alphabetical order
for word in list_of_words:
print(word + ":", frequency)
def inverse_dictionary(in_dictionary):
out_dictionary = {}
for key in in_dictionary:
value = in_dictionary[key]
if (value in out_dictionary):
list_of_keys = out_dictionary[value]
list_of_keys.append(key)
else:
out_dictionary[value] = [key]
return out_dictionary
def main():
filename = "albums.txt"
dictionary = count_words(filename)
print_word_frequencies(dictionary)
main()
Since this is an assignment, I will not give you the full code, but just point out some errors.
First, your indentation is all wrong, and indentation is important in Python! This may just have happened when you pasted your code into the question editor, but maybe not. Particularly, make sure your are not mixing tabs and spaces!
Your count_words method does not return anything, thus dictionary is None and you get TypeError: 'NoneType' object is not iterable in inverse_dictionary
When you do for line in filename, you are iterating the characters in the file name, not the lines in the file, as the global variable filename is shadowed by the filename parameter. Open the file in that method using with open(filename) as the_file:
Your process_line method seems odd. It seems like you remove all the special characters, but then how do you plan to separate band name and album name? You seem to just count words, not albums per band. Try line.split(" - ")[0] to get the band.
All that dictionary-inversing is not needed at all. In print_word_frequencies, just sort the items from the dictionary using some custom key function to sort by the count.
With those hints, you should be able to fix your program. (In case you want to know, I got your program down to about ten lines of code.)

Resources