I am having trouble trying to fix TypeError: string indices must be integers

Question:

Grades.txt file

I am currently trying to finish a assignment but I am confused on how to fix this error. I am creating a program that will analyzes grades from a file and should calculate the
average score for each distinct section (given). I receive the error for

sections[sec]["total"] = grade[grade]

grades = {'A': 100, 'B': 89, 'C': 79, 'D': 74, 'F': 69}

# this section reads the file


def calculate_average():
    file = open("grades.txt", "r")
    sections = {}
    for line in file:
        [_, sec, grade] = line.split("t")
        grade = grade.strip()
        if sec in sections:
            sections[sec]["count"] += 1
            sections[sec]["total"] += grade[grade]
        else:
            sections[sec] = {}
            sections[sec]["count"] = 1
            sections[sec]["total"] = grade[grade]
    file.close()

# This section calculates the average data based on file

    for sec, secdata in sections.items():
        avg = secdata[" total "] / secdata[" count"]
        print(" {0} : {1}".format(sec, round(avg, 2)))


if __name__ == "__main__":
    calculate_average()
Asked By: Sadaya Preston

||

Answers:

It looks like you are trying to access the value of the grade dictionary by using the value of the grade variable as a key. This won’t work because the keys of the grade dictionary are strings (e.g. ‘A’, ‘B’, ‘C’), but the value of the grade variable is also a string (e.g. ‘A’, ‘B’, ‘C’), so you are trying to use a string as an index for a dictionary.

To fix this error, you should use the grade variable directly to access the value in the grade dictionary, like this:

sections[sec]["total"] += grades[grade]

This will add the value associated with the grade string in the grades dictionary to the total field in the sections dictionary.

Here is the updated code with this change:

grades = {'A': 100, 'B': 89, 'C': 79, 'D': 74, 'F': 69}

# this section reads the file


def calculate_average():
    file = open("grades.txt", "r")
    sections = {}
    for line in file:
        [_, sec, grade] = line.split("t")
        grade = grade.strip()
        if sec in sections:
            sections[sec]["count"] += 1
            sections[sec]["total"] += grades[grade]
        else:
            sections[sec] = {}
            sections[sec]["count"] = 1
            sections[sec]["total"] = grades[grade]
    file.close()

# This section calculates the average data based on file

    for sec, secdata in sections.items():
        avg = secdata[" total "] / secdata[" count"]
        print(" {0} : {1}".format(sec, round(avg, 2)))


if __name__ == "__main__":
    calculate_average()
Answered By: CodingClown

You probably mean:

sections[sec]["total"] = grades[grade]
Answered By: Fabi

Welcome to SO

The error message you are getting is because you are trying to use the grade as a key to access the value in the grades dictionary. However, the grade variable contains the actual grade (e.g. ‘A’, ‘B’, etc.), not the key. To fix this, you need to use the grade variable to access the corresponding value in the grades dictionary, like this:

sections[sec]["total"] = grades[grade]

Here is the complete calculate_average function with this change applied:

def calculate_average():
    file = open("grades.txt", "r")
    sections = {}
    for line in file:
        [_, sec, grade] = line.split("t")
        grade = grade.strip()
        if sec in sections:
            sections[sec]["count"] += 1
            sections[sec]["total"] += grades[grade]
        else:
            sections[sec] = {}
            sections[sec]["count"] = 1
            sections[sec]["total"] = grades[grade]
    file.close()

    for sec, secdata in sections.items():
        avg = secdata[" total "] / secdata[" count"]
        print(" {0} : {1}".format(sec, round(avg, 2)))

However, I think you can optimise this function a bit better.

It is good practice to use the with statement when working with files, as it ensures that the file is properly closed even if an error occurs. This ensures that the file is automatically closed when the with block is exited, even if an error occurs.

Secondly, you can eliminate the need for the if statement inside the for loop that processes the lines in the file. Instead, the if statement is moved outside the for loop and only executed once for each section.

A third improvement would be within the format of the string. You can use the below code to round which is more pythonic.

print(" {sec} : {avg:.2f}".format(sec=sec, avg=avg))

Finally, you don’t need to unpack your variables into a list you can remove this.

I also think your variables could be renamed better to give you a final result of:

def calculate_average():
    with open("grades.txt", "r") as file:
        sections = {}
        for line in file:
            _, section, grade = line.split("t")
            grade = grade.strip()
            if section not in sections:
                sections[section] = {"count": 0, "total": 0}
            sections[section]["count"] += 1
            sections[section]["total"] += grades[grade]

    for section, section_data in sections.items():
        avg = section_data["total"] / section_data["count"]
        print(" {section} : {avg:.2f}".format(section=section, avg=avg))

Another possible improvement could be to use:

sections[section]["total"] += grades.get(grade, 0)
# rather than
sections[section]["total"] += grades[grade]

This could stop exceptions being raised if the grade is not in the dictionary but it depends on your desired behaviour.

Answered By: GAP2002
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.