Not use for loop to read the file - python

A file, grades.dat, that includes the names and grades of 10
students as shown below are given as an example.The first item is the student's name and the second item is the grade of that student. The code will read the information in the file in a dictionary where student names are keys and their grades are values. The second item in each line that represents a grade will be converted to float
when it is read as a value in the dictionary. The code is expected to print the names
and grades of the students after reading them. A grade is considered success if it
is 70 or above, and failure if it is below 70.
Grades.dat
Barbara 62.5
John 85.
Marvin 72.5
Lewis 95.
William 65.
Mary 87.5
Sandra 92.5
Jacob 60.
Leigh 75.
Pamela 67.5
file = input("Enter the file name: ")
try:
f=open(file,"r") #c=f.read()
#print(c)
except IOError:
print("file does not exist")
#print(c)

Although not a typical way of doing things... This doesn't use a For Loop:
f=open(file,"r")
while(True):
line = f.readline()
if line == '':
break
# Do stuff to make each line fit the requirements

I'm assuming you cannot use any type of loops. Just for fun, here is another solution to iterate over a list and convert it to dictionary using a list iterator and zip function:
file = input("Enter the file name: ") try:
f=open(file,"r")
# iterator to a list of lines
c=iter(f.read().split())
# zip to create name/grade pairs, then convert to dict
grades_dict = dict(zip(c,c))
print(grades_dict)
except IOError:
print("file does not exist")
I'm not sure about the remaining problem definition. Are you allowed to use a loop for printing the output? This is using list comprehension, which is technically a for loop:
print ('\n'.join(k + ": Success"
if float(v) >= 70.0 else k + ": Failure"
for k,v in grades_dict.items()))
*Edit: It is a "Generator Expression," similar to List Comprehension
https://peps.python.org/pep-0289/

Related

Is there a shorter code for the following simple file manipulation program?

The following is the problem and i have written the code.Can someone have the answer code shortened?
Suppose the file studentdata.txt contains information on grades students earned on various
assignments. Each line has the last name of a student (which you can assume is one word) and
the numeric grade that student received. All grades are out of 100 points. Students can appear
multiple times in the file.
Here’s a sample file:
Arnold 90
Brown 84
Arnold 80
Cocher 77
Cocher 100
Write a function that reads the data from the file into a dictionary. Then continue prompting the
user for names of students. For each student, it should print the average of that student’s grades.
Stop prompting when the user enters the name of a student not in the dictionary.
A sample run for the given file:
Enter name: Arnold
The average for Arnold is: 85.0
Enter name: Brown
The average for Brown is: 84.0
Enter name: Cocher
The average for Cocher is: 88.5
Enter name: Doherty
Goodbye!
Here is my code :
import os
PATH="C:/Users/user/Desktop/studentdata.txt"
fd=open("C:/Users/user/Desktop/studentdata.txt","r")
d=fd.read()
p1=r"\b[A-za-z]+\b"
p2=r"\b[0-9]+\b"
l1=re.findall(p1,d)
fd=open("C:/Users/user/Desktop/studentdata.txt","r")
l2=re.findall(p2,d)
d={}
for key,val in list(zip(l1,l2)):
if key not in d:
d[str(key)]=int(val)
else:
d[str(key)]+=int(val)
for key in d:
d[key]=d[key]/l1.count(key)
while True:
key=input("Enter name:")
if key not in d:
print("Goodbye!")
break
print("the average for "+key+" is: "+str(d[key]))
PATH = "C:/Users/user/Desktop/"
FILE = "studentdata.txt"
with open(PATH + FILE, 'r') as fp:
lines = fp.readlines()
notes_with_students = {}
for line in lines:
student = line.split()[0]
note = line.split()[1]
if student not in notes_with_students:
notes_with_students.setdefault(student, [int(note), 1])
else:
notes_with_students[student][0] += int(note)
notes_with_students[student][1] += 1
while True:
student = input("Enter name: ")
if student not in notes_with_students:
print("Goodbye!")
break
print("The average for {} is: {}".format(student, notes_with_students[student][0]/notes_with_students[student][1]))
This can be useful.

How to calculate the average score of class members in a text file? [duplicate]

This question already has answers here:
How to correctly split with multiple underscores? [duplicate]
(3 answers)
Closed 4 years ago.
For my beginners course python I got the following assignment:
In the input file, grades are listed for the geography tests of group 2b. There have been three tests of which the grades will be included in the half-yearly report that is given to the students before the Christmas break.
On each line of the input you can find the name of the student, followed by one or more under scores (’_’). These are succeeded by the grades for the tests, for example:
Anne Adema____________6.5 5.5 4.5
Bea de Bruin__________6.7 7.2 7.7
Chris Cohen___________6.8 7.8 7.3
Dirk Dirksen__________1.0 5.0 7.7
The lowest grade possible is a 1, the highest a 10. If somebody missed a test, the grade in the list is a 1.
Your assignment is to make the report for the geography course of group 2b, which should look like this:
Report for group 2b
Anne Adema has an average grade of 5.5
Bea de Bruin has an average grade of 7.2
Chris Cohen has an average grade of 7.3
Dirk Dirksen has an average grade of 4.6
End of report
This is my python code so far:
NUMBER_OF_GRADES = 3
file =open('grades1.in.txt').read().split('\n')
for scores in file:
name_numbers = (scores.split('_'))
def averages ():
for numbers in file:
sum=0
numbers = split("\n")
for num in numbers:
sum = sum + int(num)
averages = sum/NUMBER_OF_GRADES
print ('% has an average grade of %.1') %(name, averages)
Where does it go wrong? What am I missing? Am I not splitting the right way?
There's a few things wrong with your code. This maybe should be migrated to Code Review, but I'll write my answer here for now.
I will keep this as close to your version as I can so that you see how to get from where you are to a working example without needing a ton of stuff you might not have learned yet. First let's look at yours one part at a time.
file =open('grades1.in.txt').read().split('\n')
Your file is going to be a list of strings, where each string is a line in your input file. Note that if you have empty lines in your input, some of the lines in this list will be empty strings. This is important later.
for scores in file:
name_numbers = (scores.split('_'))
Works fine to split the name part of the line from the scores part of the line, so we'll keep it, but what are you doing with it here? Right now you are overwriting name_numbers with each new line in the file and never doing anything with it, so we are going to move this into your function and make better use of it.
def averages():
No arguments? We'll work on that.
for numbers in file:
Keep in mind your file is a list, where each entry in the list is one line of your input file, so this numbers in file doesn't really make sense. I think this is where you first go wrong. You want to look at the numbers in each line after you split it with scores.split('_'), and for that we need to index the result of the split. When you split your first line, you get something like:
split_line = ['Anne Adema', '', '', '', '', '', '', '', '', '', '', '', '6.5 5.5 4.5']
The first element (split_line[0]) is the name, and the last element (split_line[-1]) are the numbers, but you still have to split those out too! To get a list of numbers, you actually have to split it and then interpret each string as a number. You can do this pretty easily with a list comprehension (best way to loop in Python) like this:
numbers = [float(n) for n in split_line[-1].split(' ')]
This reads something like: first split the last element of the line at spaces to get ['6.5', '5.5', '4.5'] (note they're all strings), and then convert each value in that list into a floating-point number, and finally save this list of floats as numbers. OK, moving on:
sum=0
numbers = split("\n") # already talked about this
for num in numbers:
sum = sum + int(num)
averages = sum/NUMBER_OF_GRADES
sum is a keyword in Python, and we never want to assign something to a keyword, so something's wrong here. You can actually just call sum(my_list) on any list (actually any iterable) my_list to get the sum of all of the values in the list. To take the average, you just want to divide this sum by the length of the list, which you can get with len(my_list).
print ('% has an average grade of %.1') %(name, averages)
There are some cool newer ways to print formatted text, one of which I will show in the following, but if you are supposed to use this way then I say stick with it. That said, I couldn't get this line to work for me, so I went with something I know better.
Rewriting it into something that works:
def averages(line):
if line is '':
return # skips blank lines!
name_numbers = line.split('_') # now we split our line
name = name_numbers[0]
numbers = [float(n) for n in name_numbers[-1].split(' ')]
average = sum(numbers) / len(numbers)
print('{} has an average grade of {:.2}'.format(name, average))
And running it on your data:
file =open('grades1.in.txt').read().split('\n')
for line in file:
averages(line) # call the function on each line
# Anne Adema has an average grade of 5.5
# Bea de Bruin has an average grade of 7.2
# Chris Cohen has an average grade of 7.3
# Dirk Dirksen has an average grade of 4.6
With the result shown in the comments below the function call. One more note, you never close your file, and in fact you never save off the file handle to close it. You can get rid of any headaches around this by using the context manager syntax in Python:
with open('grades1.in.txt', 'r') as a_file:
for line in a_file:
averages(line)
This automatically handles closing the file, and will even make sure to do so if you run into an error in the middle of the block of code that executes within the context manager. You can loop through a_file because it basically acts as an iterable that returns the next line in the file each time it is accessed.
First, you are not calling your function averages at all. You should add that as the last line in your code, but you do not really need the function definition at all.
Use the with-statement to open and automatically close the file.
Next, you can use the re package to split the lines at the underscores.
You have to split the list of grades (assuming that they are separated by spaces)
You can use the built-in functions sum and len to calculate the sum and the number of grades.
In the end, it could look something like this
import re
with open('grades1.in.txt') as grades_file:
for line in grades_file:
name, grades = re.split("_+", line)
grades = [float(k) for k in grades.split()]
avg = sum(grades)/len(grades)
print("{} has an average grade of {:.2f}.".format(name, avg))
GoTN already answered your question.
To make it clear and improve a little bit you can try:
def averages(line, number_of_grades):
line_parsed = line.split('_')
numbers = [float(x) for line_parsed[-1].split(' ')]
name = line_parsed[0]
# you can use number_of_grades or len(numbers)
# Although, if the student only has 2 grades in the file,
# but it was supposed to be two the average will be wrong.
avg = sum(numbers)/number_of_grades
print("{} has an average grade of {:.2f}.".format(name, avg))
# or print(f'{name} has an average grade of {avg:.2f}')
NUMBER_OF_GRADES = 3
files =open('grades1.in.txt').read().splitlines()
for line in files:
if len(line) > 0:
averages(line, NUMBER_OF_GRADES)
Splitting the lines up is somewhat involved. The code below does it by first replacing all the "_" characters with spaces, then splits the result of that up. Since there can be a variable number of parts making up the full name, the results of this splitting are "sliced" using negative indexing which counts backwards for the end of the sequence of values.
That works by taking advantage of the fact that we know the last three items must be test scores, therefore everything before them must be parts comprising the name. This is the line doing that:
names, test_scores = line[:-NUMBER_OF_GRADES], line[-NUMBER_OF_GRADES:]
Here's the full code:
NUMBER_OF_GRADES = 3
with open('grades1.in.txt') as file:
for line in file:
line = line.replace('_', ' ').split()
names, test_scores = line[:-NUMBER_OF_GRADES], line[-NUMBER_OF_GRADES:]
name = ' '.join(names) # Join names together.
test_scores = [float(score) for score in test_scores] # Make numeric.
average_score = sum(test_scores) / len(test_scores)
print('%s has an average grade of %.1f' % (name, average_score))
Output:
Anne Adema has an average grade of 5.5
Bea de Bruin has an average grade of 7.2
Chris Cohen has an average grade of 7.3
Dirk Dirksen has an average grade of 4.6

How do I work out the difference in numbers when reading and writing to text files in python?

Alright, so I am studying python as a hobby, and I need to write a program that: should look at data for each student and calculate the number of marks a student needs to achieve the minimum score when they re-sit their exam. So I am going to say that the minimum score that a user needs to pass their exam is 85, and if a student record says 80, they would need 5. I have written the text file, and started the python code, but I have hit a dead end, any help would be greatly appreciated. Many thanks in advance!
Python:
def menu():
with open('homework.txt','r') as a_file:
contents_of_file = a_file.read()
print(contents_of_file)
input()
Text file:
emma smith,79
noah jones,32
olivia williams,26
liam taylor,91
sophia green,80
mason brown,98
Instead of reading the whole file at once, we will look at each line individually. We'll use split to divide the lines into a name and a number, then use int to convert the string of a number into a numeric type.
def menu():
target = 85
with open('homework.txt','r') as a_file:
for l in a_file:
name, number = l.split(',')
number = int(number)
print(name + ': ' + ('passed' if number>=target else str(target - number)))
input()
('passed' if number>=target else str(target - number)) is just a way of doing an if statement in one line for simple things
There is other possibilities and shorter ways, but to give you a basic understanding, this might help: This should read each line and split it at the comma.
with open('homework.txt','r') as a_file:
for line in a_file.readlines():
split_line=line.split(",")
name=split_line[0]
score=split_line[1]
YOUR CODE HERE
The pandas package is great for manipulating text files like yours. While it might be overkill for your current scenario, it may be useful to learn.
import pandas as pd
marks_needed = 85
df = pd.read_csv('homework.txt', header=None)
for name, marks in df.values:
if marks > marks_needed:
print('{} passed!'.format(name)
else:
extra_marks = marks_needed - marks
print('{} needs {} more marks'.format(name, extra_marks))

Adding horizontal space between data on a Read only script

I need my output to look nice, and it looks very sloppy.
--------Current output---------
Below are the players and their scores
John Doe 120
Sally Smooth 115
----------End current output----------
My desired output follows
-------Desired output-----------------
Below are the players and their scores
John Doe 120
Sally Smooth 115
--------End desired output-------------
my current code follows;
def main():
# opens the "golf.txt" file created in the Golf Player Input python
# in read-only mode
infile = open('golf.txt', 'r')
print("Below are the players and their scores")
print()
# reads the player array from the file
name = infile.readline()
while name != '':
# reads the score array from the file
score = infile.readline()
# strip newline from field
name = name.rstrip('\n')
score = score.rstrip('\n')
# prints the names and scores
print(name + " " + score)
# read the name field of next record
name = infile.readline()
# closes the file
infile.close()
main()
Try using the tab character to format your spaces better.
print(name + "\t" + score)
This should give you something closer to your desired output. But you may need to use two if some names are long.
You can add the names and the scores to a list and then print it as a table as
import numpy as np
name_list = ['jane doe' ,'sally smooth']
score = np.array([[102,],[106,]]) #make a numpy array
row_format ="{:>15}" * (len(name_list))
for name, row in zip(name_list, score):
print(row_format.format(name, *row))
Note: This depends on str.format()
This code will output:
jane doe 102
sally smooth 106

Reading a .txt file and sorting into categories Python 3

I am trying to access data stored in a text file and sorting the data by specific lines in the text file.
Here is the data, text in " " is not included in the text file but for reference:
741258 "This is a student ID"
CSF105 "This is a course module"
39 "This is a module mark"
CSF104
86
CSF102
71
CSF106
16
CSF103
3
CSF100
88
CSF101
50
123456
CSF100
50
CSF101
98
CSF102
74
CSF103
84
CSF104
65
CSF105
79
CSF106
100
I need to extract the Student ID then build a list of modules and marks based on that student ID and produce the average marks for that student, I am using Classes and methods to sort the data and if I input it directly via a function just using one set of data i.e.
id1 = Student("754412")
id1.addMark(Mark("CSF102", 90))
id1.addMark(Mark("CSF101", 80))
id1.addMark(Mark("CSF101", 42))
id1.addMark(Mark("CSF104", 90))
print(id1)
print("The Students average mark is: ", id1.calculateAverageMark())
It works. How do I get python to read the lines and determine which is the next student ID in the list as to not continuously read after the last mark/module for the student? I hope this makes sense.
Just loop over the open file object and use next() to get a next line in the loop to read both course and course mark.
If a line does not start with CSF then it is assumed that we started reading a new student:
with open(inputfilename) as infh:
student = Student(next(infh).strip())
# auto-strip all lines
infh = (l.strip() for l in infh)
for line in infh:
if line.startswith('CSF'):
student.addMark(Mark(line, next(infh)))
else:
# new student, output information on the previous student first
print(student)
print("The Students average mark is: ", student.calculateAverageMark())
student = Student(line)
# last student info
print(student)
print("The Students average mark is: ", student.calculateAverageMark())

Categories