0

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

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
lee-tmy
  • 47
  • 5
  • use the `print` function to check what `parts` actually is before the `IndexError`. It's possible that the first line's `parts` has less than 3 elements and you have to skip it or deal with it separately – BatWannaBe Jun 08 '19 at 19:52
  • also noticed that you did `quiz = {}` to make a dict which seems consistent with the rest of the code, but you also did `quiz = f.readline()`, which would make `quiz` a string. If you fix the `IndexError` caused by list indexing, you'll quickly run into a `TypeError` for trying to assign to a string – BatWannaBe Jun 08 '19 at 19:59

2 Answers2

1

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.

rroutsong
  • 45
  • 5
  • Sorry, I'm new to Python. Your code outputs: {'': {'Q': 'Which two colours as on the flag of Poland?', 'A': ['Red and Green', ' Blue and White', ' Green and White', ' Red and White']}, 'C': {'Q': 'C', 'A': []}, 'D': {'Q': 'D', 'A': []}} – lee-tmy Jun 08 '19 at 21:02
  • This is because of the format of the CSV input file. Can you link to the file? I am assuming a lot of things about the input file in that code. If you print out the inputs as you read them in you can design a better dictionary structure. – rroutsong Jun 08 '19 at 21:12
  • Which birthstone is associated with the month of May?,Diamond,Ruby,Emerald,Sapphire,C (LINE BREAK HERE) Which two colours as on the flag of Poland?, Red and Green, Blue and White, Green and White,Red and White – lee-tmy Jun 10 '19 at 07:52
  • here is the file: https://docs.google.com/document/d/152xSpI5oud0feUxutaQ4FQFHlUcH9_RGQJlz-5YHqkE/edit?usp=sharing – lee-tmy Jun 10 '19 at 07:58
  • You can structure the dictionary however is best. This is where the index errors are coming in. When the CSV is read in they are read into the csvvalues variables. Where index 0 is Which birthstone is associated with the month of May?, 1 is Diamond, 2 is Ruby, 3 is Sapphire, and 4 is C you can construct a suitable dictionary structure from that. – rroutsong Jun 12 '19 at 21:41
0

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:

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69