lee-tmy
lee-tmy

Reputation: 47

How to fix IndexError: list index out of range when trying to split up a csv file into a dictionary?

I'm doing this assignment but keep getting the error IndexError: list index out of range. It involves splitting up a CSV file by "," and moving it into a dictionary.

for line in f:
     parts=line.split(",")
     quiz[parts[0]]=[parts[1],parts[2].strip("\n")]

FULL CODE:

quiz={}
f=open("questions.txt","r")
quiz=f.readline()
for line in f:
     parts=line.split(",")
     quiz[parts[0]]=[parts[1],parts[2].strip("\n")]
for i in range(10): 
     print(quiz)
     ans=input("Input your answer")
     if ans==quiz[parts[4]]:
          print("Correct!")
     else:
          print("Nope, the answer is")
f.close()

I expected the CSV file to be split up and in the dictionary, but instead it came up with the error message

quiz[parts[0]]=[parts[1],parts[2].strip("\n")]
IndexError: list index out of range

NOTE:

Here is questions.txt:

Which birthstone is associated with the month of May?,Diamond,Ruby,Emerald,Sapphire,
C
Which two colours as on the flag of Poland?,Red and Green, Blue and White, Green and White, Red and White,
D

Also, if possible I'm looking to solve this problem without the csv library but if it's easier with then that's fine

Upvotes: 0

Views: 504

Answers (2)

Patrick Artner
Patrick Artner

Reputation: 51653

IndexError occure if you access a list beyond its content:

a = [1,2,3]
print(a[99]) # IndexError, has only indexes 0,1,2

You can catch the error:

try:
    print(a[99])
except IndexError:
    print("Item doesnot exist")   # this is printed

or check your list first:

if len(a)>=100:
    print(a[99])  # would avoid the error

Reading CSV often gets this kind of error if data is not of equal lenght or if you read the line after the last \n and it is empty - and you split/access it non the less.


You might want to restructure your code a bit and use namedtuples for more clarity:

Create the data:

q = "questions.txt"
with open(q,"w") as f:
    f.write("""Which birthstone is associated with the month of May?,Diamond,Ruby,Emerald,Sapphire,
C
Which two colours as on the flag of Poland?,Red and Green, Blue and White, Green and White, Red and White,
D
""") # your problem is probably here, line is read and split and accessed on [0] etc. 
     # it has no data in it -> IndexError

The quiz-code:

from collections import namedtuple 

QuizRecord = namedtuple('Quiz', 'question,a1,a2,a3,a4,solution')
# this creates a namedtuple with fields for
#   question
#   a(nswer)1   a(nswer)2   a(nswer)3   a(nswer)4
#   solution

Q = []
pos = {"A":1, "B":2, "C":3, "D":4} # map solution letter to position in parts,
                                   # 0 would be the question
with open(q) as f:
    for line in f:
        parts=line.strip("\n,").split(",")
        if not parts:
            print("Done reading lines")
            break # done reading

        # get the next line and get the correct solution from parsed parts
        sol = pos.get(next(f).strip("\n,"),-1)
        if sol == -1:
            print("Done reading lines")
            break # done reading

        # add a new namedtuple to our quizzes
        parts.append(parts[sol]) # add solution as text to ease comparisons
        Q.append(QuizRecord._make(parts))  # add a new namedtuple to Q using parts

for question, a1, a2, a3, a4, sol in Q:
    print(question)
    print("Solutions: ", '     '.join( (a1,a2,a3,a4) ))
    ans = input("Input your answer: ").lower()
    if ans == sol.lower():
        print("Correct!\n")
    else:
        print(f"Nope, the answer is {sol}\n")

Output:

Which birthstone is associated with the month of May?
Solutions:  Diamond     Ruby     Emerald     Sapphire
Input your answerEmerald
Correct!

Which two colours as on the flag of Poland?
Solutions:  Red and Green      Blue and White      Green and White      Red and White
Input your answerRed and Green
Nope, the answer is  Red and White

Documentation:

Upvotes: 0

rroutsong
rroutsong

Reputation: 45

How many columns are in your input csv? Is it formatted correctly? Can you include it here?

Instead of readline, I would suggest using the csv library, specifically the DictReader function. This will read in the csv directly into a dictionary:

import csv
with open('names.csv') as csvfile:
    reader = csv.DictReader(csvfile)
    for row in reader:
        print(row['first_name'], row['last_name'])
    f.close()

replacing first_name and last_name with your respective column headings.

Edit:

Just saw your notice about not using the csv library. Looks like there are no line breaks or headers in your csv, so you can try:

with open('questions.txt') as f:
   for line in f:
     csvvalues = line.split(',')
     print(csvvalues)

This should print out the value you're reading in and then you can assign them to a key in a dictionary:

csvdict = {
   'csv_info_one': csvvalue[0]
}

I am making a guess that the last value in the csv row refers to the question index, so this should work for a good dictionary structure:

with open('questions.txt') as f:
  questions = {}
  for line in f:
    csvvalues = line.split(',')
    csvvalues = [x.rstrip() for x in csvvalues]
    questions[csvvalues[-1]] = {
      'Q' : csvvalues[0],
      'A' : csvvalues[1:len(csvvalues)-1]
    }

  print(questions)

This makes the assumptions that the question index is the last value in the csv row, and the question is the first, and the possible answers are the remainder of the values between first and last.

Upvotes: 1

Related Questions