{"id":658,"date":"2020-08-28T14:09:31","date_gmt":"2020-08-28T19:09:31","guid":{"rendered":"https:\/\/www.brezeale.com\/?p=658"},"modified":"2020-08-28T14:20:01","modified_gmt":"2020-08-28T19:20:01","slug":"python-application-determining-which-degree-courses-a-student-is-eligible-to-enroll-in","status":"publish","type":"post","link":"https:\/\/www.brezeale.com\/?p=658","title":{"rendered":"Python Application: Determining Which Degree Courses a Student is Eligible to Enroll In"},"content":{"rendered":"\n<p>People learning to program often struggle with how to decompose a problem into the steps necessary to write a program to solve that problem. This is one of a series of posts in which I take a problem and go through my decision-making process that leads to a program.<\/p>\n\n\n\n<p>Problem: Compare the courses that a student has completed to the courses required for a degree and determine what courses the student is eligible to enroll in.  The output of the program will be<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>completed courses<\/li><li>courses remaining for degree<\/li><li>courses for which the prerequisites have been met<\/li><\/ul>\n\n\n\n<p>I assume that you understand statements, conditionals, loops, lists, strings, functions, file input\/output, and dictionaries.<\/p>\n\n\n\n<p>You can find a video with more details at <a href=\"https:\/\/www.youtube.com\/watch?v=7Ahla3KXKJA\">https:\/\/www.youtube.com\/watch?v=7Ahla3KXKJA<\/a><\/p>\n\n\n\n<br>\n\n\n\n<h3 class=\"wp-block-heading\">Design<\/h3>\n\n\n\n<p>The program will read two files and I begin my design by looking at them.  In some real-world situations you may only have a description of what the data could look like, but when given access to real data I think that there is no replacement for looking at the data in order to understand what you are working with.<\/p>\n\n\n\n<p><code>completed.txt<\/code> contains a list of the courses that the student has completed or is currently enrolled in.  The student could simply update this file each semester and re-run the program to see what they are currently enrolled in.  Here are a few lines from <code>completed.txt<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nCSE 1310\nENGL 1301\nMATH 1323\nHIST 1311\nfine arts elective\n<\/pre><\/div>\n\n\n<p>The file <code>bscs-2013.csv<\/code> lists the courses required for a Computer Science degree.  The lines beginning with a pound sign are comments for a reader and will need to be avoided when processing this information.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n# courses required for BS Computer Science, 2012-2013 catalog\n# course,category,prerequisites,notes\nENGL 1301,preprofessional,,\nENGL 1302,preprofessional,,\nMATH 1426,preprofessional,MATH 1323,\nMATH 2425,preprofessional,MATH 1426,\nPHYS 1443,preprofessional,MATH 1426,\nPHYS 1444,preprofessional,PHYS 1443|MATH 2425,\nCSE 1104,preprofessional,,\nCSE 1105,preprofessional,,\nCSE 1320,preprofessional,CSE 1104|CSE 1105|CSE 1310|MATH 1323,\nfine arts elective,general education,,note: see approved list\nHIST 1311,general education,,\nHIST 1312,general education,,\nPOLS 2311,general education,,\nPOLS 2312,general education,,\nCSE 3380,professional,CSE 2315,note: MATH 3330 can be taken instead\nCSE 4314,professional,COMS 2302,\nCSE 4316,professional,CSE 3310|CSE 3320,\n<\/pre><\/div>\n\n\n<p>In <code>bscs-2013.csv<\/code> we can see that each course line consists of four fields (some are empty):<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>the course name, e.g., CSE 3380 or a generic name like literature elective.<\/li><li>a category.  The possibilities are preprofessional, professional, or general education.  While these terms are not necessary for this problem, I included them in the data so that 1) they could be used in the future if necessary and 2) real-world data often includes extra information unnecessary for your needs that you just have to work around.<\/li><li>course prerequisites is a vertical bar-delimited field of the courses that are prerequisites to the current course.  This field plays a very important part in deciding what courses a student is eligible to enroll in.<\/li><li>notes are additional information for some courses, such as &#8220;see approved list&#8221;.<\/li><\/ul>\n\n\n\n<p>When designing, I think of there being three parts: the first part is the input, which in this case are the two previously described files.  The last part is the expected output.  The middle part is how the input is transformed into the output.  This also typically includes thoughts of data structures.  Data structures are ways of organizing data.  There are many data structures, each with its own pros and cons.  For very simple things, such as printing a sequence of numbers, there really is no need to store anything beyond the current number.  But for larger problems you may need to store the input as well as generated values before eventually producing output.  This requires some form of data structure and you choose a data structure that will help you get from input to output.<\/p>\n\n\n\n<p>To help me answer the data structure question, I will work through a sample problem using some of the data above.  The point is to understand how I make my decisions and then translate this into instructions for the computer.<\/p>\n\n\n\n<p>I&#8217;m going to work my way down the list of courses in <code>bscs-2013.csv<\/code>, checking if they have already been taken and if not, have the prerequisites for it been taken.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>ENGL 1301 &#8212; on the list of completed courses, so move on<\/li><li>ENGL 1302 &#8212; not taken and it has no prerequisites, so I am eligible to take it<\/li><li>MATH 1426 &#8212; not taken and it has a prerequisite of MATH 1323 which I have taken, so I am eligible to take it and need to print any notes (none in this case)<\/li><li>MATH 2425 &#8212; not taken and it has a prerequisite of MATH 1426.  Since I have not taken MATH 1426, I am not eligible to take it<\/li><\/ul>\n\n\n\n<p>So what information from <code>bscs-2013.csv<\/code> did I need to make my decisions?  I needed the course name, the list of prerequisites, and will eventually need any notes associated with an eligible course.  Even though I don&#8217;t need it for this problem, I chose to also store the category since including it was little additional work and it could potentially be useful for something else.<\/p>\n\n\n\n<p>This leads to two possible data structures.  The first is a 2D list, where the information for a course is contained within a list.  It might look something like this (where the internal values are really strings):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n&#x5B; &#x5B;ENGL 1301,preprofessional,,],\n  &#x5B;ENGL 1302,preprofessional,,],\n  &#x5B;MATH 1426,preprofessional,MATH 1323,],\n  &#x5B;MATH 2425,preprofessional,MATH 1426,],\n  &#x5B;CSE 1320,preprofessional,CSE 1104|CSE 1105|CSE 1310|MATH 1323,],\n  &#x5B;fine arts elective,general education,,note: see approved list] ]\n<\/pre><\/div>\n\n\n<p>The second data structure is a dictionary with the course name the key.  So how can I store the other three things as the value?  Use a dictionary as the value.  It might look like this:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n{ ENGL 1301 : { category : preprofessional,\n                prereqs  : &quot;&quot;,\n                notes    : &quot;&quot; },\n  CSE 1320  : { category : preprofessional,\n                prereqs  : CSE 1105|CSE 1310|MATH 1323,\n                notes    : &quot;&quot; },\n  fine arts elective : { category : general education,\n                         prereqs  : &quot;&quot;,\n                         notes    : see approved list }\n}\n<\/pre><\/div>\n\n\n<p>I chose the dictionary option since it is easy to extract the keys from the dictionary, sort them, and then process the courses by key.  Here is the pseudocode that I produced based upon my design:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n# read data\nopen degree file\nfor each line\n  if not comment\n    tokenize line\n    store line in dictionary\nopen completed courses file\nfor each line\n  tokenize line\n  store line in list\n\n# print courses completed and remaining\nfor course completed\n  print course\n     \nfor course in degree\n  if course not completed\n    print course\n\n# print courses for which you have prereqs\nfor each degree course\n  if course not completed\n    if prereqs met \n      print degree course\n<\/pre><\/div>\n\n\n<br>\n\n\n\n<h3 class=\"wp-block-heading\">Final Program<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#####################################\ndef getData(filenameReqs, filenameComp) :\n    ##  read data\n    degreeDict = { }\n    \n    fp = open(filenameReqs, &quot;r&quot;)\n    for line in fp :\n        line = line.strip()  # get rid of white space\n                             # at both ends\n        if line&#x5B;0] != &quot;#&quot; :  # if line is not a comment\n            course, category, prereqs, notes = line.split(&#039;,&#039;)\n            degreeDict&#x5B;course] = {&quot;category&quot; : category, \n                                  &quot;prereqs&quot; : prereqs,\n                                  &quot;notes&quot; : notes}\n    fp.close()\n    \n    ### get list of courses completed (or currently enrolled in)\n    completedList = &#x5B; ]\n\n    fp = open(filenameComp, &quot;r&quot;)\n    for line in fp :\n        completedList.append( line.strip() )\n    fp.close()\n\n    completedList.sort()\n\n    return degreeDict, completedList\n\n#####################################\ndef printData( degreeDict ) :\n    # purpose: print course information (used for testing)\n    #   input: dictionary \n    # returns: nothing\n    keys = degreeDict.keys()\n    keysList = sorted(keys)\n    \n    for k in keysList :\n        print(k)\n        inner = degreeDict&#x5B;k].keys()\n        innerList = sorted(inner)\n        for i in innerList :\n            print(&quot; %-15s : %s&quot; % (i, degreeDict&#x5B;k]&#x5B;i]))\n\n        print()\n\n#####################################\ndef printCompleted( completedList ) :\n    # purpose: print course information\n    #   input: list \n    # returns: nothing\n    print(&quot;COURSES COMPLETED&quot;)\n    print(&quot;-----------------&quot;)\n    for c in completedList :\n        print(&quot;  &quot;, c)\n\n#####################################\ndef printRemaining( degreeDict, completedList ) :\n    # purpose: print course information\n    #   input: dictionary, list \n    # returns: nothing\n    print(&quot;COURSES REMAINING&quot;)\n    print(&quot;-----------------&quot;)\n    keys = degreeDict.keys()\n    keysList = sorted(keys)\n    for c in keysList :\n        if c not in completedList :\n            print(&quot;  &quot;, c)\n\n#####################################\ndef printEligible( degreeDict, completedList ) :\n    # purpose: print course information\n    #   input: dictionary, list \n    # returns: nothing\n    &quot;&quot;&quot;\n          for each degree course\n            if course not completed\n              if prereqs met \n                print degree course\n    &quot;&quot;&quot;\n    eligibleList = &#x5B; ]\n    \n    for c in degreeDict :\n        if c not in completedList :\n            #print(&quot;***  %s  ***&quot; % c)\n            t = degreeDict&#x5B;c]&#x5B;&quot;prereqs&quot;].split(&#039;|&#039;)\n            eligible = True  # assume eligible unless missing\n                             #   prereq found\n            for p in t :\n                if p not in completedList :\n                    eligible = False  # found missing prereq\n\n            if eligible or t&#x5B;0] == &quot;&quot; :\n                eligibleList.append( c )\n\n    eligibleList.sort()\n\n    print(&quot;COURSES ELIGIBLE TO TAKE&quot;)\n    print(&quot;------------------------&quot;)\n    for c in eligibleList :\n        if degreeDict&#x5B;c]&#x5B;&quot;notes&quot;] != &quot;&quot; :\n            print(&quot;   %s (%s)&quot; % (c, degreeDict&#x5B;c]&#x5B;&quot;notes&quot;]))\n        else :\n            print(&quot;  &quot;, c)\n\n\n######################################\n#####            main            #####\nfilenameReqs = &quot;bscs-2013.csv&quot;\nfilenameComp = &quot;completed.txt&quot;\n\ndegreeDict, completedList = getData(filenameReqs, filenameComp)\n\n&quot;&quot;&quot;\n# use for testing that degree information is being read correctly\nprintData( degreeDict )\nexit()\n&quot;&quot;&quot;\n\n##  print courses completed\nprintCompleted( completedList )\n\n\n##  print courses remaining\nprint()\nprintRemaining( degreeDict, completedList )\n    \n## print courses for which you have prereqs\nprint()\nprintEligible( degreeDict, completedList )\n<\/pre><\/div>","protected":false},"excerpt":{"rendered":"<p>People learning to program often struggle with how to decompose a problem into the steps necessary to write a program to solve that problem. This is one of a series of posts in which I take a problem and go through my decision-making process that leads to a program. Problem: Compare the courses that a student has completed to the courses required for a degree and determine what courses the student is eligible to enroll in. The output of the&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.brezeale.com\/?p=658\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[9,5],"tags":[],"class_list":["post-658","post","type-post","status-publish","format-standard","hentry","category-programming","category-python-programming"],"_links":{"self":[{"href":"https:\/\/www.brezeale.com\/index.php?rest_route=\/wp\/v2\/posts\/658","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.brezeale.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.brezeale.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.brezeale.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.brezeale.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=658"}],"version-history":[{"count":10,"href":"https:\/\/www.brezeale.com\/index.php?rest_route=\/wp\/v2\/posts\/658\/revisions"}],"predecessor-version":[{"id":671,"href":"https:\/\/www.brezeale.com\/index.php?rest_route=\/wp\/v2\/posts\/658\/revisions\/671"}],"wp:attachment":[{"href":"https:\/\/www.brezeale.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=658"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.brezeale.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=658"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.brezeale.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=658"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}