Data Structures and Algorithms using Python
Copyright © 2023 by Rance Necaise
Table Of Contents
Data Structures and Algorithms using Python
Copyright © 2023
by Rance Necaise

1.11 Application: Student Records

Most computer applications are written to process and manipulate data that is stored external to the program. Data is commonly extracted from files stored on disk, from databases, and even from remote sites through web services. For example, suppose we have a collection of records stored on disk that contain information related to students at Smalltown College. We have been assigned the task to extract this information and produce a similar to the following in which the records are sorted by identification number.

                             LIST OF STUDENTS                 

            ID     NAME                       CLASS       GPA
            =====  =========================  ==========  ====
            10015  Smith, John                Sophomore   3.01
            10167  Jones, Wendy               Junior      2.85
            10175  Smith, Jane                Senior      3.92
            10188  Wales, Sam                 Senior      3.25
            10200  Roberts, Sally             Freshman    4.00
            10208  Green, Patrick             Freshman    3.95
            10226  Nelson, Amy                Sophomore   2.95
            10334  Roberts, Jane              Senior      3.81
            10387  Taylor, Susan              Sophomore   2.15
            10400  Logan, Mark                Junior      3.33
            10485  Brown, Jessica             Sophomore   2.91
            ==================================================
            Number of students: 11

Our contact in the Registrar's office, who assigned the task, has provided some information about the data. We know each record contains five pieces of information for an individual student: (1) the student's id number represented as an integer; (2) their first and last names, which are strings; (3) an integer classification code in the range [1 ... 4] that indicates if the student is a freshman, sophomore, junior, or senior; and (4) their current grade point average represented as a floating-point value. What we have not been told, however, is how the data is stored on disk. It could be stored in a plain text file, in a binary file, or even in a database. In addition, if the data is stored in a text or binary file, we will need to know how the data is formatted in the file, and if it's in a relational database, we will need to know the type and the structure of the database.

Designing a Solution

Even though we have not yet been told the type of file or the format used to store the data, we can begin designing and implementing a solution by working with an abstraction of the input source. No matter the source or format of the data, the extraction of data records from external storage requires similar steps: open a connection, extract the individual records, then close the connection. To aide in our effort, we define a Student File Reader ADT to represent the extraction of data from an external file or database. In computer programming, an object used to input data into a program is sometimes referred to as a reader while an object used to output data is referred to as a writer.

The Student File Reader ADT

A student file reader is used to extract student records from external storage. The five data components of the individual records are extracted and stored in a storage object specific for this collection of student records.

  • StudentFileReader(filename)

    Creates a student reader instance for extracting student records from the given file. The type and format of the file is dependent on the specific implementation.

  • open()

    Opens a connection to the input source and prepares it for extracting student records. If a connection cannot be opened, an exception is raised.

  • close()

    Closes the connection to the input source. If the connection is not currently open, an exception is raised.

  • fetchRecord()

    Extracts the next student record from the input source and returns a reference to a storage object containing the data. None is returned when there are no additional records to be extracted. An exception is raised if the connection to the input source was previously closed.

Creating the Report

The program in the listing below uses the Student File Reader ADT to produce the sample report illustrated earlier. The program extracts the student records from the input source, sorts the records by student identification number, and produces the report. This program illustrates some of the advantages of applying abstraction to problem solving by focusing on the "what" instead of the "how."

Program Listing
  1. # Produces a student report from data extracted from an external source.
  2. from studentfile import StudentFileReader
  3.  
  4. FILE_NAME = "students.txt"   # Name of the file to open.
  5.  
  6. def main() :
  7.   studentList = loadRecords(FILE_NAME)
  8.    # Sort the list by id number. Each object is passed to the lambda
  9.    # expression which returns the idNum field of the object.
  10.   studentList.sort( key = lambda rec: rec.idNum )
  11.   printReport(studentList)
  12.        
  13. # Read all of the student records and store them in a list.
  14. def loadRecords(filename) :
  15.    # Create and open a file reader.
  16.   reader = StudentFileReader(FILE_NAME)
  17.   reader.open()
  18.  
  19.    # Read the student records from the text file.
  20.   studentList = []
  21.   record = reader.fetchRecord()
  22.   while record is not None :
  23.     studentList.append(record)
  24.     record = reader.fetchRecord()
  25.    
  26.   reader.close()
  27.   return studentList
  28.  
  29. # Prints the student report.  
  30. def printReport(theList) :
  31.    # The class names associated with the class codes.
  32.   classNames = (None, "Freshman", "Sophomore", "Junior", "Senior")  
  33.  
  34.    # Print the header.
  35.   print("LIST OF STUDENTS".center(50))
  36.   print("")
  37.   print("%-5s  %-25s  %-10s  %-4s" % ('ID', 'NAME', 'CLASS', 'GPA' ))
  38.   print("%5s  %25s  %10s  %4s" % ('-' * 5, '-' * 25, '-' * 10, '-' * 4))
  39.    # Print the body.
  40.   for record in theList :
  41.     print("%5d  %-25s  %-10s  %4.2f" %
  42.                   (record.idNum,
  43.                    record.lastName + ', ' + record.firstName,
  44.                    classNames[record.classCode], record.gpa))
  45.    # Add a footer.
  46.   print("-" * 50)  
  47.   print("Number of students:", len(theList))
  48.  
  49. # Executes the main routine.
  50. main()

By using the Student File Reader ADT, we are able to design a solution and construct a program for the problem at hand without knowing exactly how the data is stored in the external source. We import the StudentFileReader class from the studentfile module, which we assume will be an implementation of the ADT that handles the actual data extraction. Further, if we want to use this same program with a data file having a different format, the only modifications required will be to indicate a different module in the import statement and possibly a change to the file name specified by the constant variable FILE_NAME.

The studentreport program consists of three functions. The loadRecords function uses an instance of the ADT to connect to the external source in order to extract the student records into a list. The list is returned to the main routine where it is then sorted in ascending order based on the student identification number. The actual report is produced by passing the sorted list to the printReport function.

Storage Class

When the data for an individual student is extracted from the input file, it will need to be saved in a storage object that can be added to a list in order to first sort and then print the records. We could use tuples to store the records, but we avoid the use of tuples when storing structured data since it's better practice to use classes with named fields. Thus, we define the StudentRecord class to store the data related to an individual student:

class StudentRecord :
  def __init__( self ):
    self.idNum = 0
    self.firstName = None
    self.lastName = None
    self.classCode = 0
    self.gpa = 0.0

Implementation

The ADT has to be implemented to extract data based on the format in which the data is stored. For this example, we are going to extract the data from a text file in which the records are listed one after the other. The five fields of the record are each stored on a separate line. The first line contains the id number, the second and third contain the first and last names, the fourth line contains the classification code, and the grade point average follows on the fifth line. The following text block illustrates the format for a file containing two records:

      10015
      John
      Smith
      2
      3.01
      10334
      Jane
      Roberts
      4
      3.81
      10208
      Patrick
      Green
      1
      3.95

The listing at the bottom of the page provides the implementation of the ADT for extracting the records from the text file in the given format. The constructor simply initializes an instance of the class by creating two attributes, one to store the name the text file and the other to store a reference to the file object after it's opened. The open method is responsible for opening the input file using the name saved in the constructor. The resulting file object is saved in the _inputFile instance variable so it can be used in the other methods. After the records are extracted, the file is closed by calling the close method.

The actual extraction of a record from the text file is handled by the fetchRecord method. To extract the student records from a file in which the data is stored in a different format, we need only modify this method to accommodate the new format.

The Student File Reader ADT provides a framework that can be used to extract any type of records from a text file. The only change required would be in the fetchRecord method to create the appropriate storage object and to extract the data from the file in the given format.

Program Listing
Program: studentfile.py
  1. # Implementation of the StudentFileReader ADT using a text file as the
  2. # input source in which each field is stored on a separate line.
  3.  
  4. class StudentFileReader :  
  5.    # Create a new student reader instance.
  6.   def __init__(self, inputSrc) :
  7.     self._inputSrc = inputSrc
  8.     self._inputFile = None
  9.    
  10.    # Open a connection to the input file.
  11.   def open(self) :
  12.     self._inputFile = open(self._inputSrc, "r")
  13.    
  14.    # Close the connection to the input file.
  15.   def close(self) :
  16.     self._inputFile.close()
  17.     self._inputFile = None
  18.        
  19.    # Extract the next student record from the file.
  20.   def fetchRecord(self) :                    
  21.      # Read the first line of the record.
  22.     line = self._inputFile.readline()
  23.     if line == "" :  
  24.       return None
  25.      
  26.      # If there is another record, create a storage object and fill it.
  27.     student = StudentRecord()
  28.     student.idNum = int(line)
  29.     student.firstName = self._inputFile.readline().rstrip()
  30.     student.lastName = self._inputFile.readline().rstrip()
  31.     student.classCode = int(self._inputFile.readline())
  32.     student.gpa = float(self._inputFile.readline())
  33.     return student                          
  34.          
  35. # Public storage class used for an individual student record.
  36. class StudentRecord :
  37.   def __init__(self) :
  38.     self.idNum = 0
  39.     self.firstName = None
  40.     self.lastName = None
  41.     self.classCode = 0
  42.     self.gpa = 0.0
Page last modified on July 30, 2023, at 08:14 PM