Rachael
Rachael

Reputation: 13

Using the first row of a CSV as the keys in nested dictionaries?

Please don't be brutal! I'm new to coding and have looked all over the web to find answers. I have a CSV with column one listing names, column 2 listing jobs, and column 3 listing birth months. I want the output I typed below the code. I have the dictionary made, but it is in this format: {"Karen Fisher": ("IT","November"), etc.} I want the keys of the nested dictionaries to be from the header of the csv so that people know what kind of data they are looking at about each person. I'm getting this error: "TypeError: 'tuple' object does not support item assignment"

with open("Example1.csv", "r") as csvfile:
    csvreader = csv.reader(csvfile, delimiter=',')
    row1  = next(csvreader)
    #print(row1)

    def makeadictionary(csvreader):
        dct = {}
        keys = []
        valuesdict = {}
        names = []
        next(csvreader)
        for row in csvreader:
            keys.append(row[0])
            dct[row[0]] = row[1],row[2]
            names.append(row[0])
        #print(names)
        for key,value in dct.items():
            value = list(value)
            #print(value)
            job = value[0]
            #print(job)
            birthmonth = value[1]  
            #print(birthmonth)
            dct[key][row1[1]] = job
            dct[key][row1[2]] = birthmonth
        return dct
    print(makeadictionary(csvreader))

Goal output: {"Karen Fisher":{"job": "IT", "birth month": "November"}, etc.}

Upvotes: 0

Views: 1087

Answers (2)

leo
leo

Reputation: 106

Take a look at the following line in your code:

dct[row[0]] = row[1],row[2]

This creates a a dictionary of the following form:

{"Karen Fisher": ("IT", "November")}

Note that "Karen Fisher" maps to a tuple of size 2, that is, if you access dct["Karen Fisher"] you get the tuple ("IT", "November"). Now look at the line causing the error:

dct[key][row1[1]] = job

We know that dct[key] is equal to ("IT", "November") and that row1[1] is equal to "job", so what python is trying to execute is the following expression:

("IT", "November")["job"] = job

So the structure of this is a[b] = c where a is a tuple. This doesn't work for a couple of reasons, one of them that you can't do an indexed assignment of that form for a tuple (tuples can only be created, but not modified), the other is that you can't index a tuple with a string.

What you seem to want to do is to assign an item in a dictionary, but you don't have a dictionary in hand: dct is a dictionary, but dct[key] is a tuple. What you can do is instead create a dictionary:

dct[key] = {row1[1]: job, row1[2]: birthmonth]}

This should work, but there's another little issue. It's generally not good practice to modify a dictionary while you're iterating through it. You also don't need to iterate through everything twice. And I think you have a bug where you skip your first line of data after the header (in the next(csvreader) call in makeadictionary). Finally, you don't need to create a nested function for what you want to accomplish.

What I would recommend is the following:

 with open("Example1.csv", "r") as csvfile:
    csvreader = csv.reader(csvfile, delimiter=',')
    header_row  = next(csvreader)
    result = {}
    for row in csvreader:
      name = row[0]
      result[name] = {}
      for field_name, value in zip(header_row[1:], row[1:]):
        # The zip function 'mixes' the two lists:
        # zip([a, b, c], [d, e, f]) == [(a, d), (b, e), (c, f)]
        result[name][field_name] = value
  print(result)

Upvotes: 1

Tim Roberts
Tim Roberts

Reputation: 54718

The csv.DictReader class will return you a dictionary. All you have to do is store the entries by key:

from pprint import pprint
import csv

f = open('x.csv','r')

track = {}
for row in csv.DictReader(f):
    track[row['name']] = dict(row)

pprint( track )

Output:

{'Joe Blow': {'birth month': 'April', 'job': 'HR', 'name': 'Joe Blow'},
 'Karen Fisher': {'birth month': 'November',
                  'job': 'IT',
                  'name': 'Karen Fisher'}}

Upvotes: 1

Related Questions