#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    16
    Rep Power
    0

    Could anyone help me on a Python programming assignment?


    Hello, I have been working on an assignment and Iv gotten stuck and can't figure out what to fix.

    The assignment:

    Write a program that will read an unknown number of bowlers and their bowling scores (with possible values from 1 to 300) from an external file called "bowlingscores.txt". The file will look similar to the following:
    David
    102
    Hector
    300
    Mary
    195
    Jane
    160
    Sam
    210

    Output the bowlers’ names to an external data file called "bowlingaverages.txt". Next to each bowler's name, print a message dependent on their scores:
    For perfect scores (equal to 300), output “perfect”
    For those scores greater than the average score, output “above average”
    For those below average, output “below average”
    Your program must include at least one function (e.g., to calculate the average, to determine the appropriate message to print, etc.).



    Here is what I have so far:

    Code:
    
    def bowling_scores(filename):
        infile = open(filename, "r")
        bowling_info = []
        count = 0
        for line in infile:
            parts = line.split("/n") 
            count += 1
            if count == 1 or count % 2 == 1:
                info["name"] = parts[0]
            if count % 2 == 0:
                info["score"] = int(parts[0])
            bowling_info.append(info)
        infile.close()
        return bowling_info
    def bowling_avg(filename):
        outfile = open(filename, "r")
        bowling_avg = []
        for key in sorted(bowling_info):
           score = bowling_info["score"]
           avg_score = (sum(score) / len(score))
           avg = ""
           if score == 300:
               avg = "perfect"
               bowling_avg.append(avg)
           elif score > avg_score:
               avg = "above average"
               bowling_avg.append(avg)
           elif score < avg_score:
               avg = "below average"
               bowling_avg.append(avg)
        outfile.close()  
        return bowling_avg
        
    outfile = open("bowling_avg.txt", "w")
    for key in sorted(bowling_avg):
        outfile.write("%s %s\n" % (bowling_info[name], avg))
  2. #2
  3. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,931
    Rep Power
    481
    I'll modify your first function to return a list of dictionaries.
    Code:
    def bowling_scores(filename):
        infile = open(filename, "r")
        bowling_info = []
        count = 0
        for line in infile:
            parts = line.split("\n")
            count += 1
            if count == 1 or count % 2 == 1:
                info = dict(name=parts[0])  ########## make a new dictionary
            if count % 2 == 0:
                info["score"] = int(parts[0])
                bowling_info.append(info)  ####### indent this line!
        infile.close()
        return bowling_info
    I have a file named bs with your sample data.
    I call your function, and display the result, and I suggest you use this list of dictionaries as the input argument to the other function. Looks like this:
    Code:
    >>> bi = bowling_scores('bs')
    >>> import pprint
    >>> pprint.pprint(bi)
     {'name': 'David', 'score': 102},
     {'name': 'Hector', 'score': 300},
     {'name': 'Mary', 'score': 195},
     {'name': 'Jane', 'score': 160},
     {'name': 'Sam', 'score': 210}]
    >>>
    I'd have made a dictionary keyed by name with a list of scores as the value for each key, but your list of little dictionaries is workable. Good luck!
    [code]Code tags[/code] are essential for python code and Makefiles!
  4. #3
  5. Commie Mutant Traitor
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Jun 2004
    Location
    Alpharetta, GA
    Posts
    1,806
    Rep Power
    1570
    Oh, this is actually pretty close, in a lot of ways. Unfortunately, it also shows a number of serious misunderstandings with how Python works, ones which newcomers often have but which you'll need to get past to finish the problem. Let's start with the bowling_scores() function. Here, the biggest issue IMHO is that you are using a list for the data, but then treating it as if it were a dictionary.

    Code:
    import sys
    
    def bowling_scores(filename):
        """ A function to collect the bowling scores
            from the input file and returns it in a dictionary.
                key == player's name
                value == player's score
        """
        try:
            infile = open(filename, "r")
        except:
            print("Could not read file '{0}'. Exiting.".format(filename))
            sys.exit(-1)
    
        bowling_info = dict()
        count = 0
        for line in infile:
            parts = line.split("\n")
            count += 1
            if count % 2 == 1:
                name = parts[0]               # odd line, get just the player's name
            else:
                score = int(parts[0])         # even line, get the player's score
                bowling_info[name] = score    # and store it in the dictionary keyed to name
        infile.close()
        return bowling_info
    This was, I think, simply a confusion over what kind of data structure you were intending to use.

    Note the use of the documentation string or docstring: if you put a string, either a regular one or a triple-quote multi-line string, immediately after the declaration part of a function, it is treated as the documentation for that function. The same applies to methods, classes, and modules, in fact.

    For the second function, I think you are trying to fit too much into the same function, and getting snarled as a result. I would break it up into two functions, one of which simply returns the average, the other (which calls that function) which actually does the writing to the file.
    Code:
    def avg_score(scores):
        """ Function which takes a dictionary of bowling player's names and scores
            and returns the average of the scores (type float).
        """
        denominator = len(scores)
        numerator = 0
        for name in scores.keys():
            numerator += scores[name]
        return numerator / denominator
    
    
    def bowling_averages(scores):
        """ Function that takes a scores dictionary
            and returns a list of strings describing the score
            relative to the average score.
        """
        scoreAverage = avg_score(scores)
        scoreDescriptions = list()
    
        for player in sorted(scores.keys()):
            score = scores[player]
            description = ''
            if score == 300:
               description = "perfect"
            elif score > scoreAverage:
               description = "above average"
            elif score == scoreAverage:
               description = "average"
            else:
               description = "below average"
            scoreDescriptions.append('{0}: {1}'.format(player, description))
    
        return scoreDescriptions
    Finally, you'll need to re-write the __main__ section to reflect the changes made:
    Code:
    if __name__ == "__main__":
        scores = bowling_scores("bowlingscores.txt")
        descriptions = bowling_averages(scores)
    
        try:
            outfile = open("bowlingaverages.txt", "w")
        except:
            print("Could not open file 'bowling_averages.txt'. Exiting.")
            sys.exit(-1)
    
        for line in descriptions:
            print(line)
            outfile.write(line + '\n')
        outfile.close()
    (NB: None of this is tested code, so I may well have made a mistake myself. Test it out careful before you submit anything.)
    Last edited by Schol-R-LEA; November 4th, 2012 at 06:41 PM.
    Rev First Speaker Schol-R-LEA;2 JAM LCF ELF KoR KCO BiWM TGIF
    #define KINSEY (rand() % 7) λ Scheme is the Red Pill
    Scheme in ShortUnderstanding the C/C++ Preprocessor
    Taming PythonA Highly Opinionated Review of Programming Languages for the Novice, v1.1

    FOR SALE: One ShapeSystem 2300 CMD, extensively modified for human use. Includes s/w for anthro, transgender, sex-appeal enhance, & Gillian Anderson and Jason D. Poit clone forms. Some wear. $4500 obo. tverres@et.ins.gov
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    16
    Rep Power
    0
    I appreciate everyone's help! I'm learning a lot. I have to keep in mind that sometimes when I look at code written by people that have been doing this much longer than I have, I can't just copy what yalls code says. I have to truly sit down and learn what yall are saying, because I have to then take the concept of it and simplify it into a more beginner level code. Otherwise, my instructor would just think I copied someone and didn't learn anything.

    I made some revisions, and this is the error I am getting:

    line 35, in <module>
    for key in sorted(bowling_avg):
    TypeError: 'function; object is not iterable

    My code reads:

    Code:
    def bowling_scores(filename):
        infile = open(filename, "r")
        bowling_info = []
        count = 0
        for line in infile:
            parts = line.split("/n") 
            count += 1
            if count == 1 or count % 2 == 1:
                info = dict(name=parts[0])
            if count % 2 == 0:
                info["score"] = int(parts[0])
                bowling_info.append(info)
        infile.close()
        return bowling_info
    def bowling_avg(filename):
        outfile = open(filename, "r")
        bowling_avg = []
        for key in sorted(bowling_info):
           score = bowling_info["score"]
           avg_score = (sum(score) / len(score))
           avg = ""
           if score == 300:
               avg = "perfect"
               bowling_avg.append(avg)
           elif score > avg_score:
               avg = "above average"
               bowling_avg.append(avg)
           elif score < avg_score:
               avg = "below average"
               bowling_avg.append(avg)
        outfile.close()  
        return bowling_avg
        
    outfile = open("bowling_avg", "w")
    for key in sorted(bowling_avg):
        outfile.write("%s %s\n" % (bowling_info[name], avg))
  8. #5
  9. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,931
    Rep Power
    481
    Perhaps my post was too subtle.

    Where you have

    for key in sorted(bowling_avg):

    bowling_avg is a function. You didn't call the function to get its return value. How do we know? Of course the error message says so. I find that printing the type and value of the object in doubt right before the error helps.

    print(str(type(bowling_avg)));print(str(bowling_avg))# new line 35
    for key in sorted(bowling_avg):

    That might help you understand a little bit.
    Your bowling_avg function needs a string argument, which it uses to open a file for read access with the unlikely named variable "outfile" but you don't use outfile except to close it later. As scholar-LEA says, close but there's a lot of misunderstanding in there.

    As I said before, passing the list of little dictionaries created by bowling_scores into bowling_avg makes a lot more sense. And as Scholar-LEA said, you'll need to change your main code to actually call bowling_scores. Defining a function doesn't invoke that function. You need to call the function, just like you knew to do with
    open(filename, "r")
    [code]Code tags[/code] are essential for python code and Makefiles!
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    16
    Rep Power
    0
    Thanks, I see what your saying. Ill work on it some more and ill post what I come up with. I appreciate it.
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Nov 2012
    Posts
    16
    Rep Power
    0
    ok this is what I have come up with. I' afraid that I have gotten too lost and will have to just start fresh. What do you think?

    Code:
    def bowling_scores(filename):
        infile = open(filename, "r")
        bowling_info = []
        count = 0
        for line in infile:
            parts = line.split("/n") 
            count += 1
            if count == 1 or count % 2 == 1:
                name = parts[0]
            else:
                score = int(parts[0])
                bowling_info[name] = score
        infile.close()
        return bowling_info
    
    def avg_score(scores):
        denominator = len(scores)
        numerator = 0
        for name in scores.keys():
            numerator += scores[name]
        return numerator / denominator
        
    def bowling_averages(scores):
    
       
        scoreAverage = avg_score(scores)
        scoreDescriptions = list()
    
        for player in sorted(scores.keys()):
            score = scores[player]
            description = ''
            if score == 300:
               description = "perfect"
            elif score > scoreAverage:
               description = "above average"
            elif score == scoreAverage:
               description = "average"
            else:
               description = "below average"
            scoreDescriptions.append('{0}: {1}'.format(player, description))
    
        return scoreDescriptions
    
        
    scores = bowling_scores("bowlingscores.txt")
    descriptions = bowling_averages(scores)    
    outfile = open("bowling_avg.txt", "w")
    for line in description:
        outfile.write(line + "/n" )
    outfile.close()
  14. #8
  15. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,931
    Rep Power
    481
    I think that you need to actually let python process your program. You'll soon start to learn how to use the python error messages.

    I checked only Hector, your output was correct for Hector.

    Anyway, you're program is now pretty close, I fixed it with small changes, and marked the lines I changed with comments. Please run your original program and try to figure out why the changes I made were important.

    Also, I'm quite sure I can create an input file that will produce different answers when run on python2 versus python3. It may be subtle but in your next program you'll probably ask why 3/2 is 1.

    Also, 1%2 is 1.

    Also, your program limitation (based on the way I modified it) is one game per player. That might be given in the problem statement. Or you could call this a feature, saying that only the last entry per player is counted and therefor the input is particularly easy to edit.

    Also, that's all the alsos.
    Code:
    import sys
    
    def bowling_scores(filename):
        infile = open(filename, "r")
        bowling_info = dict()                    # was list()   #[]
        count = 0
        for line in infile:
            parts = line.split("/n")
            count += 1
            if count == 1 or count % 2 == 1:
                name = parts[0]
            else:
                score = int(parts[0])
                bowling_info[name] = score
        infile.close()
        return bowling_info
    
    def avg_score(scores):
        denominator = len(scores)
        numerator = 0
        for name in scores.keys():
            numerator += scores[name]
        return numerator / denominator
    
    def bowling_averages(scores):
        scoreAverage = avg_score(scores)
        scoreDescriptions = list()
        for player in sorted(scores.keys()):
            score = scores[player]
            description = ''
            if score == 300:
               description = "perfect"
            elif score > scoreAverage:
               description = "above average"
            elif score == scoreAverage:
               description = "average"
            else:
               description = "below average"
            scoreDescriptions.append('{0}: {1}'.format(player, description))
        return scoreDescriptions
    
    if 'linux' in sys.platform:
        filename = '/tmp/bs'
    else:
        filename = "bowlingscores.txt"
    
    scores = bowling_scores(filename)
    
    descriptions = bowling_averages(scores)
    outfile = open("bowling_avg.txt", "w")
    for line in descriptions:                 # descriptions was singular
        outfile.write(line + "\n" )           # was  "/n"
    outfile.close()
    [code]Code tags[/code] are essential for python code and Makefiles!
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2014
    Posts
    4
    Rep Power
    0

    Unhappy


    Originally Posted by b49P23TIvg
    I think that you need to actually let python process your program. You'll soon start to learn how to use the python error messages.

    I checked only Hector, your output was correct for Hector.

    Anyway, you're program is now pretty close, I fixed it with small changes, and marked the lines I changed with comments. Please run your original program and try to figure out why the changes I made were important.

    Also, I'm quite sure I can create an input file that will produce different answers when run on python2 versus python3. It may be subtle but in your next program you'll probably ask why 3/2 is 1.

    Also, 1%2 is 1.

    Also, your program limitation (based on the way I modified it) is one game per player. That might be given in the problem statement. Or you could call this a feature, saying that only the last entry per player is counted and therefor the input is particularly easy to edit.

    Also, that's all the alsos.
    Code:
    import sys
    
    def bowling_scores(filename):
        infile = open(filename, "r")
        bowling_info = dict()                    # was list()   #[]
        count = 0
        for line in infile:
            parts = line.split("/n")
            count += 1
            if count == 1 or count % 2 == 1:
                name = parts[0]
            else:
                score = int(parts[0])
                bowling_info[name] = score
        infile.close()
        return bowling_info
    
    def avg_score(scores):
        denominator = len(scores)
        numerator = 0
        for name in scores.keys():
            numerator += scores[name]
        return numerator / denominator
    
    def bowling_averages(scores):
        scoreAverage = avg_score(scores)
        scoreDescriptions = list()
        for player in sorted(scores.keys()):
            score = scores[player]
            description = ''
            if score == 300:
               description = "perfect"
            elif score > scoreAverage:
               description = "above average"
            elif score == scoreAverage:
               description = "average"
            else:
               description = "below average"
            scoreDescriptions.append('{0}: {1}'.format(player, description))
        return scoreDescriptions
    
    if 'linux' in sys.platform:
        filename = '/tmp/bs'
    else:
        filename = "bowlingscores.txt"
    
    scores = bowling_scores(filename)
    
    descriptions = bowling_averages(scores)
    outfile = open("bowling_avg.txt", "w")
    for line in descriptions:                 # descriptions was singular
        outfile.write(line + "\n" )           # was  "/n"
    outfile.close()
    I don't know why there is an error: invalid syntax at line # for name in scores.keys():
  18. #10
  19. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,931
    Rep Power
    481
    Yes, this is an invalid COBOL program.
    [code]Code tags[/code] are essential for python code and Makefiles!

IMN logo majestic logo threadwatch logo seochat tools logo