List not being overwritten in expected manner - python

I am new to Python. What my code is supposed to do is check the line against an existing list, if the line is not already in the location file it asks for the user to assign a value to it and updates the list it is validating against. I have verified that the lists are reading from the text files correctly (in the below format).
The result it is giving me is a never-ending loop because it is not finding the line in the list even after it has been added. I would expect it to break after the user enters 'n' and then some string value.
(Also there will be an additional line for if dummyvar in location:, but I haven't gotten to that yet.)
Variables
from_location = [ company, address, city, state ] #changes line by line
location = [[ 'company a', 'address a', 'city a', 'state a', 'classification a'],
[ 'company b', 'address b', 'city b', 'state b', 'classification b']]
loc_opt = ['classification a', 'classification b', 'classification c']
Code snippet:
while from_location not in location[:][0:-1]:
ftext=("This location has not been indexed. Please enter the " +
"location name or input one of these prompts \n" +
" 'l' to list all acceptable locations\n" +
" 'n' to add a new location\n" +
" 'p' to print the full line of information\n" +
"Company: " + str(from_location[0]) + " \n" +
"Address: " + str(from_location[1]) + "\n" +
"City: " + str(from_location[2]) + "\n" +
"State: " + str(from_location[3]) + "\n")
dummyvar = input(ftext)
if dummyvar == "l":
print("Current Location Options are: \n ")
for item in loc_opt:
print(" ", item ," ")
if dummyvar == "p":
print("Entire Line : ", spline,"\n")
if dummyvar == "n":
new_location=input("Please input new location:\n")
new_location.upper()
new_location = [new_location]
loc_opt = loc_opt + new_location
location = location + [from_location + new_location]
print(location)
Full Code
print("Press Ctrl C with the Python window selected \n"
"at any time to stop the program. A loud beep "
"will sound \n when the program is finished.\n\n")
date = 00000000
counter = 1
dummyvar="q"
ref_fp =(r"filepath")
loc_opt_fn = open(ref_fp + "LOCATION OPTIONS.txt")
loc_ref_fn = open(ref_fp + "LOCATION REFERENCE.txt")
loc_opt = loc_opt_fn.read().split("\n")
location = loc_ref_fn.read().split("\n")
for index in range(len(location)):
location[index]=location[index].split("\t")
while len(str(date))!= 8 or (date < 20180101 or date > 20301231):
date = input("What date is the file would you like to clean"
"( yyyymmdd year like: 20190227). \n\n")
date = str(date).strip()
try:
date = int(date)
except:
print("\nNo letters please!\n")
date = 000
fp1 = (r"anotherfilepath")
fp2 = ( r" filename.txt")
fpr= (r"yetanotherfilepath")
filepath = fp1 + str(date) + fp2
with open(filepath) as source:
for line in source:
line.strip("\n")
spline = line.split("\t")
if counter == 1:
spline.append("FROM")
spline.append("TO")
else:
spline.append("")
spline.append("")
if spline[0] == "NC":
#So we've added two columns, FROM and To
#And we are only operating on the lines that are NC
#Because that excludes the exceptions.
#Now we want to check and see if the From and
#To information is in the reference lists.
from_location=[spline[5],spline[7],spline[9],spline[10]]
to_location=[spline[13],spline[15],spline[17],spline[18]]
while from_location not in location[:][0:-1]:
ftext=("This location has not been indexed. Please enter the " +
"location name or input one of these prompts \n" +
" 'l' to list all acceptable locations\n" +
" 'n' to add a new location\n" +
" 'p' to print the full line of information\n" +
"Company: " + str(from_location[0]) + " \n" +
"Address: " + str(from_location[1]) + "\n" +
"City: " + str(from_location[2]) + "\n" +
"State: " + str(from_location[3]) + "\n")
dummyvar = input(ftext)
if dummyvar == "l":
print("Current Location Options are: \n ")
for item in loc_opt:
print(" ", item ," ")
if dummyvar == "p":
print("Entire Line : ", spline,"\n")
if dummyvar == "n":
new_location=input("Please input new location:\n")
new_location.upper()
new_location = [new_location]
loc_opt = loc_opt + new_location
location = location + [from_location + new_location]
print(location)
counter += 1
import winsound
winsound.Beep(600,500)
print("\n\n\n----------------------------Processing is finished.----------------------------\n\n\n")

location[:][0:-1]doesn't remove the last element from each element of location. It's equivalent to temp = location[:] followed by temp[0:-1]. temp is just a copy of location, and then it returns a list with all but the last element of that.
You can do what you want with a list comprehension:
while from_location not in [l[0:-1] for l in location]:

Related

How can I number the lines of a .txt file and edit certain information from a selected line? (Python)

I have a .txt file with the names and information as below
John, 87, 64, 72, 79, 81, Yes
Steve, 32, 45, 29, 37, 34, No
I am trying to read from the .txt file and number each name so that the specific name can be selected by entering the number and information from the selected name can be edited.
I want to be able to choose from two options "to edit one of the amounts" or "change from No to Yes"
line_count = 0
with open("results.txt", 'r') as r_file:
for line in r_file:
results_info = line.split(",")
line_count += 1
print("\n" + str(line_count) + " " + " Name:\t" + results_info[0]
+ "\n " + "Subject_1:\t " + results_info[1]
+ "\n " + "Subject_2:\t" + results_info[2]
+ "\n " + "Subject_3:\t" + results_info[3]
+ "\n " + "Subject_4:\t" + results_info[4]
+ "\n " + "Subject_5:\t" + results_info[5]
+ "\n " + "Pass?\t" + results_info[6])
student_select = input("\nEnter the number of the student to edit: ")
I've gotten this far but I am stuck when it comes to the rest.
edit:
Never added subject 5 to the code
I would like to write the changes made back to the .txt file
Sorry, I don't think that I was clear enough. I'd like to display the list of all the students numbered. From there give the option to select a student by entering their number and then the option to edit a grade or change pass to yes.
So you have 3 tasks here: read data, manage user input, save data if something has been modified.
And the best structure to handle this is a dict of lists (I kept to your idea of numbering the rows, but you could easily have the student's name as key instead). The code could be something like this (some more checks are needed on user input, of course):
def edit_info(fname):
#read data
with open(fname, 'r') as r_file:
info = {}
for i,line in enumerate(r_file):
info[str(i)] = line.rstrip().split(', ')
#prompt user and update data
dirty = False
while True:
for k,vl in info.items():
print(f'{k:2} {vl[0]:10} {" ".join(vl[1:-1])} {vl[-1]:3}')
student = input('Enter Student number or X to exit... ')
if student == 'X':
break
if student in info:
while True:
subject = input('Enter Subject number, P to set pass to yes, or X to stop editing... ')
if subject == 'X':
break
if subject == 'P':
info[student][-1] = 'Yes'
dirty = True
elif '1' <= subject <= str(len(info[student])-1):
subject = int(subject)
newvalue = input(
f'Enter new value for Student {student} for Subject {subject} (currently {info[student][subject]})... ')
info[student][subject] = newvalue
dirty = True
#save data if needed
if dirty:
with open(fname, 'w') as w_file:
for vl in info.values():
w_file.write(', '.join(vl)+'\n')
print('Completed')
I'm new to Python too so I will do it in a stupid way sorry. Here is my code which changes all the info of the nth student as all the input you made
def select_student_to_edit(input_num):
all_result=[]
result0 = input('Edit name element: ')
result1 = " " + input('Edit 1th element: ')
result2 = " " + input('Edit 2th element: ')
result3 = " " + input('Edit 3th element: ')
result4 = " " + input('Edit 4th element: ')
result5 = " " + input('Edit 5th element: ')
result6 = " " + input('Edit Yes/No element: ') + "\n"
with open('test1', 'r+') as f:
if input_num>1:
for i in range(1,input_num):
all_result.append(f.readline()) #If input_num = n then read n-1 line before, add all of the to a all_result list contain all lines
#Start modifying the line(student) that you want to:
results_info = f.readline().split(",") #Split all info into list to modify
results_info[0] = result0
results_info[1] = result1
results_info[2] = result2
results_info[3] = result3
results_info[4] = result4
results_info[5] = result5
results_info[6] = result6
all_result.append(",".join(results_info)) #add modified studen to all_result list
#Add all rest lines into all_result list
rest_line = f.readlines()
for line in rest_line:
all_result.append(line)
print(all_result)
#Write all line(student) in all_result into the old file
with open('test1','w+') as f:
for line in all_result:
f.write(line)
select_student_to_edit(int(input('Enter the student you want to change info (nth): ')))

How to divide numbers from a text file?

This is my file text:
Covid-19 Data
Country / Number of infections / Number of Death
USA 124.356 2.236
Netherlands 10.866 771
Georgia 90 NA
Germany 58.247 455
I created a function to calculate the ratio of deaths compared to the infections, however it does not work, because some of the values aren't floats.
f=open("myfile.txt","w+")
x="USA" + " " + " " + "124.356" + " " + " " + "2.236"
y="Netherlands" + " " + " " + "10.866" + " " + " " + "771"
z="Georgia" + " " + " " + "90" + " " + " " + "NA"
w="Germany" + " " + " " + "58.247" + " " + " " + "455"
f.write("Covid-19 Data" + "\n" + "Country" + " " + "/" + " " + "Number of infections" + " " + "/" + " " + "Number of Death" + "\n")
f.write(x + "\n")
f.write(y + "\n")
f.write(z + "\n")
f.write(w)
f.close()
with open("myfile.txt", "r") as file:
try:
for i in file:
t = i.split()
result=float(t[-1])/float(t[-2])
print(results)
except:
print("fail")
file.close()
Does someone have an idea how to solve this problem ?
You can do the following:
with open("myfile.txt", "r") as file:
for i in file:
t = i.split()
try:
result = float(t[-1]) / float(t[-2])
print(result)
except ValueError:
pass
At the time you don't know if the values you are trying to divide are numeric values or not, therefore surrounding the operation with a try-catch should solve your problem.
If you want to become a bit more "clean" you can do the following:
def is_float(value):
try:
float(value)
except ValueError:
return False
return True
with open("myfile.txt", "r") as file:
for i in file:
t = i.split()
if is_float(t[-1]) and is_float(t[-2]):
result = float(t[-1]) / float(t[-2])
print(result)
The idea is the same, however.
I used the same file that you attached in your example. I created this function hopefully it helps:
with open("test.txt","r") as reader:
lines = reader.readlines()
for line in lines[2:]:
line = line.replace(".","") # Remove points to have the full value
country, number_infections, number_deaths = line.strip().split()
try:
number_infections = float(number_infections)
number_deaths = float(number_deaths)
except Exception as e:
print(f"[WARNING] Could not convert Number of Infections {number_infections} or Number of Deaths {number_deaths} to float for Country: {country}\n")
continue
ratio = number_deaths/number_infections
print(f"Country: {country} D/I ratio: {ratio}")
As you can see I avoided the headers of your file using lines[2:] that means that I will start from row 3 of your file. Also, added try/exception logic to avoid non-float converts. Hope this helps!
Edit
Just noticed that the format for thousands is used with "." instead "," in that case the period was removed in line 7.
The results for this execution is:
Country: USA D/I ratio: 0.017980636237897647
Country: Netherlands D/I ratio: 0.07095527332965212
[WARNING] Could not convert Number of Infections 90.0 or Number of Deaths NA to float for Country: Georgia
Country: Germany D/I ratio: 0.007811561110443456
Fixed the following:
The first two lines in your text-file are headers. These need to be skipped
'NA' Can't be converted to zero
If there is a 0 in your data, your program would crash. Now it wouldn't.
f=open("myfile.txt","w+")
x="USA" + " " + " " + "124.356" + " " + " " + "2.236"
y="Netherlands" + " " + " " + "10.866" + " " + " " + "771"
z="Georgia" + " " + " " + "90" + " " + " " + "NA"
w="Germany" + " " + " " + "58.247" + " " + " " + "455"
f.write("Covid-19 Data" + "\n" + "Country" + " " + "/" + " " + "Number of infections" + " " + "/" + " " + "Number of Death" + "\n")
f.write(x + "\n")
f.write(y + "\n")
f.write(z + "\n")
f.write(w)
f.close()
with open("myfile.txt", "r") as file:
#Skipping headers
next(file)
next(file)
try:
for i in file:
t = i.split()
#Make sure your code keeps working when one of the numbers is zero
x = 0
y = 0
#There are some NA's in your file. Strings not representing
#a number can't be converted to float
if t[1] != "NA":
x = t[1]
if t[2] != "NA":
y = t[2]
if x == 0 or y == 0:
result = 0
else:
result=float(x)/float(y)
print(t[0] + ": " + str(result))
except:
print("fail")
file.close()
Output:
USA: 55.615384615384606
Netherlands: 0.014093385214007782
Georgia: 0
Germany: 0.12801538461538461
Your header line in the file is Covid-19 Data. this is the first line and when you call t=i.split() you then have a list t which has data ['Covid-19', 'Data']
you cannot convert these to floats since they have letters in them. Instead you should read the first 2 header line before the loop and do nothing with them. However you are then going to have issues with Georgia as "NA" also cannot be converted to a float.
A few other points, its not good practice to have a catch all exception. Also you dont need to close the file explicitly if you open the file using a with statement.

Python 3: read file of names, create new file with first names and last names reverse

I am a noob to python and am stuck on a simple task. I looked at similar questions on stackoverflow but was not able to apply to my own problem. I have created a file with a list of names. How do I create a new file where it reads the original file (pretending that I don't know how many names are in the file) and reverses the names (people are in same order but with last name before first name). Below is my script:
firstname1 = "Morty"
lastname1 = "Smith"
fullname1 = firstname1 + " " + lastname1
firstname2 = "Donna"
lastname2 = "Gueterman"
fullname2 = firstname2 + " " + lastname2
firstname3 = "Beth"
lastname3 = "Smith"
fullname3 = firstname3 + " " + lastname3
firstname4 = "Rick"
lastname4 = "Sanchez"
fullname4 = firstname4 + " " + lastname4
firstname5 = "Little"
lastname5 = "Dipper"
fullname5 = firstname5 + " " + lastname5
formal_names = fullname1,fullname2,fullname3,fullname4,fullname5
f = open("names_normal.txt","w")
f.write("%s " % (formal_names, ))
f.close()
def reverse_list(lst):
new = []
count = len(lst)-1
while count >=0:
new.append(lst[count])
count -= 1
return new
x = reverse_list(formal_names)
n = open("names_new.txt","w")
n.write("%s " % (x, ))
n.close()
These are my results:
1st file:
('Morty Smith', 'Donna Gueterman', 'Beth Smith', 'Rick Sanchez',
'Little Dipper')
2nd file: ('Little Dipper', 'Rick Sanchez', 'Beth Smith', 'Donna Gueterman', 'Morty Smith')
What I want: ('Smith Morty', 'Gueterman Donna', 'Smith Beth', 'Sanchez Rick', 'Dipper Little')
Any help would be appreciated! Thank you so much!
def reverse_list(lst):
new = []
for name in lst:
temp = name.split(" ")
new += [temp[1]+" "+temp[0]]
You're just changing order of words in the array, you should change order of the name and surname with splitting from space.
def reverse_name(name):
# Try to fill here and update if doesn't work
def reverse_list(lst):
new = []
for name in lst:
new.append(reverse_name(name))
return new
This is how I attacked this problem. It's probably best to put this in a function as mentioned above.
firstname1 = "Morty"
lastname1 = "Smith"
fullname1 = firstname1 + " " + lastname1
firstname2 = "Donna"
lastname2 = "Gueterman"
fullname2 = firstname2 + " " + lastname2
firstname3 = "Beth"
lastname3 = "Smith"
fullname3 = firstname3 + " " + lastname3
firstname4 = "Rick"
lastname4 = "Sanchez"
fullname4 = firstname4 + " " + lastname4
firstname5 = "Little"
lastname5 = "Dipper"
fullname5 = firstname5 + " " + lastname5
formal_names = [fullname1,fullname2,fullname3,fullname4,fullname5]
reversed = []
for i in range(0, (len(formal_names))):
rev = formal_names[i].split()
rev_name = rev[1] + ' ' + rev[0]
reversed.append(rev_name)
print(reversed)
['Smith Morty', 'Gueterman Donna', 'Smith Beth', 'Sanchez Rick', 'Dipper Little']
now you just write the list to a file
with open('output.txt', 'w') as file:
for name in reversed:
file.write(name)
You are complicating matters using separate variables for each person's name. In Python the better way of handling this is to use one of python's data structures, in this case a list with each name contained in a tuple. The advantage of doing this is that you can iterate over the list and refer to parts of the name by position, for example: names[0][1] for "Smith".
names = [("Morty","Smith"),
("Donna","Gueterman"),
("Beth","Smith"),
("Rick","Sanchez"),
("Little","Dipper")]
Or, if you wish you can used a namedtuple to make things clear, especially if you add other data items for each person.
import collections
Person = collections.namedtuple('Person', 'first last')
names = [Person("Morty","Smith"),
Person("Donna","Gueterman"),
Person("Beth","Smith"),
Person("Rick","Sanchez"),
Person("Little","Dipper")]
The output can then be created with a list comprehension :
normal = ", ".join([name.first + " " + name.last for name in names])
reversed = "; ".join([name.last + ", " + name.first for name in names])
print(normal)
print(reversed)
You can alter the punctuation : the first string ", " is between names, the second string " " is between words. Then, use the method suggested in earlier answers to store the strings in a file.
(I would advise using punctuation between last and first otherwise you can run into problems with names like "Alan Simon".)

Python file processing?

My assignment was to write a program which extracts the first/last names, birth year, and ID from a file, manipulate that information to create a username and formatted ID, prompt the user for 3 test grades, calculate the average, and finally write all the information to a new file. This is the program I wrote, and the error I got is listed below the program.
Define main function
def main():
infile = open("studentinfo.txt", "r")
data = infile.read()
fName, lName, ID, year = data.split(",")
year = int(year)
Prompt the user for three test scores
grades = eval(input("Enter the three test scores separated by a comma: "))
Create a username
uName = (lName[:4] + fName[:2] + str(year)).lower()
converted_id = ID[:3] + "-" + ID[3:5] + "-" + ID[5:]
grade_1, grade_2, grade_3 = grades
Convert the grades to strings so they can be written to a new file
[grade_1, grade_2, grade_3] = [str(grade_1), str(grade_2), str(grade_3)]
Calculate the average
average =(grade_1 + grade_2+ grade_3)/3
Convert the average to a string
average = str(average)
Write the information the file
outfile = open("studentreport.txt", "w")
outfile.write("*******Student Report*******\nStudent Name:" + fName + " " + lName)
outfile.write("\nStudent ID: " + converted_id + "\n" + "Username: " + uName + "\n\n")
outfile.write("Grade 1: " + grade_1 + "\n" "Grade 2: " + grade_2 + "\n" + "Grade 3: " + grade_3 + "\n" + "Average: " + average)
infile.close()
outfile.close()
main()
Traceback (most recent call last):
File "C:/Users/ovi/Desktop/Python Project 1.py", line 34, in
main()
File "C:/Users/ovi/Desktop/Python Project 1.py", line 22, in main
average =(grade_1 + grade_2+ grade_3)/3
TypeError: unsupported operand type(s) for /: 'str' and 'int'
You need to convert your converted string grades to floats (or int)
average =(float(grade_1) + float(grade_2)+ float(grade_3))/3.0
average = str(average)
You need to convert the variables of type int to strings.
outfile.write("Grade 1: " + str(grade_1) + "\n" "Grade 2: " + str(grade_2) + "\n" + "Grade 3: " + str(grade_3) + "\n" + "Average: " + str(average))
OR
You could simply do like this..
>>> gr1 = 23
>>> gr2 = 45
>>> gr3 = 56
>>> total = gr1+gr2+gr3
>>> avg = total/3
>>> l = [gr1, gr2, gr3, total, avg]
>>> print("GRade 1: {} grade 2: {} grade 3: {} total: {} average : {}".format(*l))
GRade 1: 23 grade 2: 45 grade 3: 56

Python passed values from a list not adding correctly

In my Code below I am having issues with 2 things. For one The math in the function on lines 40 (examPoints) and 47 (hwkPoints) is being passed a range of values in a list on line 94. It should be taking the scores and adding them up but for some reason it isn't adding the last number on each range passed.
ex: for myValues[11:13] it is being passed the numbers 75, 95, and 97 but it only adds the first 2 and not the last.
My code is here:
from time import asctime
from time import localtime
def findGrade(myGrade): #argument number in range of 1 - 100 or float myNum?
if myGrade >= 90:
letterGrade = "A"
if myGrade >= 80:
letterGrade = "B"
if myGrade >= 70:
letterGrade = "C"
if myGrade >= 60:
letterGrade = "D"
if myGrade < 60:
letterGrade = "F"
return letterGrade
def calculatePointsEarned(hwkGrades, examGrades):
hwkTotal = float(hwkPoints(hwkGrades))
#print hwkTotal
examTotal = float(examPoints(examGrades))
#print examTotal
myAverage = (hwkTotal + examTotal) / possiblePoints
myAverage = myAverage * 100.0
#myAverage = int(myAverage)
return myAverage
def totalPoints(hwkGrades, examGrades):
hwkTotal = int(hwkPoints(hwkGrades))
examTotal = int(examPoints(examGrades))
allPoints = str((hwkTotal + examTotal))
return allPoints
#Create newtimeline using day of week, space, month, space, day, space, year, space time from asctime function
def timeMessage():
localtime()
newTimeline = asctime()
return newTimeline
def examPoints(examValues):
myGrades = 0
for grade in examValues:
myGrades = int(grade) + myGrades
#print str(myGrades) + " exam\n"
return myGrades
def hwkPoints(hwkValues):
myGrades = 0
for grade in hwkValues:
myGrades = int(grade) + myGrades
#print str(myGrades) + " hwk"
return myGrades
def requestMessage (myValues, myTime):
nameLine = myValues[1] + ", " + myValues[2] + "\t" + myValues[0] + "\t" + myValues[3]
examScore = "Exam " + "- " + myValues[11] + ", " + myValues[12] + ", " + myValues[13]
hwkScore = "Homework " + "- " + myValues[4] + ", " + myValues[5] + ", " + myValues[6] + ", " + myValues[7] + ", " + myValues[8] + ", " + myValues[9] + ", " + myValues[10]
pointsEarned = "Total points earned " + "- " + totalPoints(myValues[4:10], myValues[11:13])
myGrade = "Grade: " + str(theAverage) + " that is a " + findGrade(theAverage)
message = nameLine + "\n" + examScore + "\n" + hwkScore + "\n" + pointsEarned + "\n" + myGrade + "\n" + myTime
return message
def fileOutput(studentID, lastName, firstName, dateTime):
myLine = studentID + " " + lastName + ", " + firstName + " " + dateTime + "\n"
return myLine
#Create input stream from grades.dat and assign to infile
inFile = open('grades.dat', "r")
#Create output stream to results.dat and assign to outfile
outFile = open('results.dat', 'w+')
myTime = timeMessage()
theAverage = 0
theLettergrade = ""
theMessage = ""
possiblePoints = 550
theRequest = ""
studentID = raw_input("Please input student ID: ")
myLine = "notemptystring"
while myLine != "": #may be wrong Is myline not equal to the empty string?
myLine = inFile.readline() #may be wrong Read line from infile and assign to myline
myLine = myLine.strip('\r\n')
myValues = myLine.split(",") #Separate values in myline and assign to myvalues
if studentID == myValues[0]:
#print myValues
#Call calculatePointsEarned function with a list of homework values and a list of exam values and assign to theaverage
theAverage = calculatePointsEarned(myValues[4:10], myValues[11:13])
#print theAverage
theLettergrade = findGrade(theAverage) #Call findGrade function with theaverage and assign to thelettergrade)
#print theLettergrade
#Call fileOutput function with studentid, lastname, firstname, and datetime to get message for writing to output file, and assign to therequest
theRequest = fileOutput(myValues[0], myValues[1], myValues[2], timeMessage())
#print theRequest
theMessage = requestMessage(myValues, timeMessage()) #Call requestMessage with myline and mytime for message to display, and assign to themessage
#Write theRequest to outfile
outFile.write(theRequest)
print theMessage
else: #is studentid not equal to first element in myValues
"Do Nothing"
#close infile and outfile
inFile.close()
outFile.close()
Edit: Sorry for the link I was having problems getting the code to look right on here.
for myValues[11:13] it is being passed the numbers 75, 95, and 97 but it only adds the first 2 and not the last
myValues[11:13] selects two elements, not three. The end index (13) is not included in the range.
Have a read of Explain Python's slice notation

Categories

Resources