user3059474
user3059474

Reputation: 47

Error: list index out of range

I'm working with CSV files and here is what I have so far. I get an error that my index is out of range. It finishes the first for loop and then messes up. I am trying to populate a dictionary.

def read_table(file):
    line = file.readline()
    line = line.strip()
    keylist = line.split(',')
    d = {}
    for key in keylist:
        if key not in d:
            d[key] = []
    while line != '':
        line = file.readline()
        line = line.strip()
        val = line.split(',')
        for i in keylist:
            index = keylist.index(i)
            d[keylist[index]].append(val[index])
    return d

Upvotes: 1

Views: 419

Answers (1)

abarnert
abarnert

Reputation: 366123

Your while loop isn't going to break as soon as line becomes empty, it's just going to check that at the start of each loop.

So, when you've read all but the last line, you do this:

while line != '': # the last line wasn't empty
    line = file.readline() # but now this one is
    line = line.strip()
    val = line.split(',') # so this returns a single value
    for i in keylist:
        index = keylist.index(i) # so this raises an IndexError
        d[keylist[index]].append(val[index])

The smallest fix is to put the check directly after each readline:

while True:
    line = file.readline()
    line = line.strip()
    if not line:
        break
    val = line.split(',') # so this returns a single value
    for i in keylist:
        index = keylist.index(i) # so this raises an IndexError
        d[keylist[index]].append(val[index])

(Note that if there's a blank line in the middle of your file, you will return early instead of raising an error, because you're checking line after the line = line.strip(), so you can no longer distinguish between an empty line, '\n', and end-of-file, ''. If that's a problem, just move the test up one line.)

A better fix would be to just iterate over the file: for line in file: does exactly what you want the loop to do, without having to deal with readline and checking for empty strings and breaking from a loop and so on.

But a much better fix would be to use the csv module and let it do what it does:

d = defaultdict(list)
reader = csv.DictReader(file)
for line in reader:
    for key, value in line.items():
        d[key].append(value)
return d

Or, alternatively, just build a list of dicts (which you can do with list_o_dicts = list(reader)), then convert it to a dict of lists at the end.

Upvotes: 2

Related Questions