Coke
Coke

Reputation: 985

Cannot access nested dictionary in python

Introduction:

I am trying to access nested dictionary element in python, which looks like this:

{'CA':{'1':'3','2':'3','3':'3'},'IL': {'1':'31','2':'45','3':'23'},...}

Firstly I read from Excel file, where I get names of states and then assign a dictionary to each state. This is how I do it:

xls_file = pd.ExcelFile('D:/CollegeScorecardDataDictionary-08-18-2016.xlsx')
dfEx = xls_file.parse('Church')  # Parse Church sheet
for (i, item) in enumerate(stateName):
     if stateChurchDict.get(item)<>None:
            continue 
     else:
            stateChurchDict[item] = dict

Once loop is iterated, I have something like this:

{'CA':<type dict>,'IL': <type dict>,'AL': <type dict>...}

In each state there are lots of churches which can be categorized in either '1', '2' or '3' This is where I got the numbers in the nested dictionaries.

My problem is I want to refer to a nested dictionary of certain state like

stateChurchDict['AL']['3']

and get the number of churches under category '3' in a certain state. However, firstly I have to check if it empty or not, if it is empty the value has to be added. Thus, I came up with this:

for (i, item) in enumerate(stateName):
            if stateChurchDict[stateName[i-1]]['3'] <> None:
                stateChurchDict.update({stateChurchDict[stateName[i-1]]['3']: stateChurchDict[stateName[i-1]]['3'] + 1})
            else:
                stateChurchDict[stateName[i-1]]['3'] = 1

BUT, this stateChurchDict[stateName[i-1]]['3'] cannot access the nested dictionary, however stateName[i-1] == 'AL' and it calls the element like stateChurchDict['AL']['3'] and still nothing.

Any help is greatly appreciated.

I am posting the whole stuff for a better explanation:

import pandas as pd
from collections import defaultdict, Counter
def IsNumeric(x):
    try:
        float(x)
        return x
    except:
        return 0
xls_file = pd.ExcelFile('D:/CollegeScorecardDataDictionary-08-18-2016.xlsx')
dfEx = xls_file.parse('Church')  # Parse data_dictionary sheet
dfCsv = pd.read_csv('D:/MERGED2014_15_PP.csv', low_memory=False)
churchCode = dfEx.Code  # Label column
churchName = dfEx.ChurchName  # Value column
churchCategory = dfEx.Category  # Church category
relafil = dfCsv.RELAFFIL  # Religious Id in CSV
stateName = dfCsv.STABBR  # Name of state
churchList = {}  # Create dictionary to store churches
stateChurchDict = defaultdict(Counter)  # Create dictionary to store churches by state
stateChurchTemp = {} #Sepate dictionary for churches by state
# Put values into dictionary
for (i, v) in enumerate(churchCode):
    churchList[v] = churchCategory[i] #Assigns a category to each church in state

for (i, item) in enumerate(stateName): #Create a dictionary as a value to each state in the stateChurchList dictionary
    if item <> None:
        if stateChurchDict.get(item) <> None:
            continue
        else:
            stateChurchDict[item] = {}

for (i, item) in enumerate(stateName): #Iterate through states and count the number of churches by categories. Once the state name is changed, the number needs to be transferred from stateChurchTemp to stateChurchDict
    if IsNumeric(relafil[i]) <> 0:
        if i >= 1 and item <> stateName[i - 1]:
            if stateChurchDict[stateName[i - 1]][3] <> None:
                stateChurchDict.update({stateChurchDict[stateName[i - 1]][3]: stateChurchDict[stateName[i - 1]][
                                                                                    3] + IsNumeric(
                    stateChurchTemp[3])})
            else:
                stateChurchDict[stateName[i - 1]][3] = IsNumeric(stateChurchTemp[3])
            if stateChurchDict[stateName[i - 1]][2] <> None:
                stateChurchDict.update({stateChurchDict[stateName[i - 1]][2]: stateChurchDict[stateName[i - 1]][
                                                                                    2] + IsNumeric(
                    stateChurchTemp[2])})
            else:
                stateChurchDict[stateName[i - 1]][2] = IsNumeric(stateChurchTemp[2])
            if stateChurchDict[stateName[i - 1]][1] <> None:
                stateChurchDict.update({stateChurchDict[stateName[i - 1]][1]: stateChurchDict[stateName[i - 1]][
                                                                                    1] + IsNumeric(
                    stateChurchTemp[1])})
            else:
                stateChurchDict[stateName[i - 1]][1] = IsNumeric(stateChurchTemp[1])
        if churchList.get(relafil[i]) <> None and stateChurchTemp.get(churchList.get(relafil[i])) <> None:
            stateChurchTemp.update({churchList.get(relafil[i]): stateChurchTemp.get(churchList.get(relafil[i])) + 1})
        else:
            stateChurchTemp[churchList.get(relafil[i])] = 1
print stateChurchDict

Upvotes: 2

Views: 407

Answers (3)

jbakirov
jbakirov

Reputation: 1056

You are not calling the nested dictionary, you trying to update the main one. Please change this line:

stateChurchDict.update({stateChurchDict[stateName[i - 1]][2]: stateChurchDict[stateName[i - 1]][2] + IsNumeric(stateChurchTemp[2])})

with this:

stateChurchDict.get(statename[i-1]).update({3: stateChurchDict[stateName[i - 1]][3] + IsNumeric(stateChurchTemp[3])})

Upvotes: 1

Coke
Coke

Reputation: 985

Alright, this is how I came to answer. Simply, I created another dictionary internalDict, which stores nested dictionary's values.

Instead of calling stateChurchDict[stateName[i-1][3]] I tried internalDict = stateChurchDict[stateName[i-1]], and afterwards worked only with internalDict. As a result, was calling stateChurchDict[stateName[i-1][3]] like internalDict[3].

Upvotes: 1

Moses Koledoye
Moses Koledoye

Reputation: 78556

stateChurchDict should probably not have been a vanilla dictionary in the first place.

A collections.Counter passed to a collections.defauldict is the right direction here:

>>> from collections import defaultdict, Counter
>>> d = defaultdict(Counter) # or defaultdict(lambda: defaultdict(int))
>>> d['AL']['3']
0

With this, default count values are generated on the fly for keys nested up to two levels, and your code reduces to:

from collections import defaultdict, Counter

stateChurchDict = defaultdict(Counter)
for i, item in enumerate(stateName):
    stateChurchDict[stateName[i-1]]['3'] += 1

Upvotes: 1

Related Questions