2

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
12
  • Where did you see <>? Commented Oct 23, 2016 at 22:11
  • @PadraicCunningham A deprecated form of !=. Still works in Py2 Commented Oct 23, 2016 at 22:12
  • '<type dict>' is a new dictionary, which is not yet populated with data. Commented Oct 23, 2016 at 22:12
  • Use '3' in stateChurchDict[stateName[i-1] to check if '3' is present in the dict or not. Commented Oct 23, 2016 at 22:12
  • @RustamUmarov, assign it as stateChurchDict[item] = {}, you may find a collections.defaultdict is your friend here. Also your enumerate is redundantr and you could just create the dict as {item:{} for item in stateName } Commented Oct 23, 2016 at 22:14

3 Answers 3

1

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])})
Sign up to request clarification or add additional context in comments.

Comments

1

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

3 Comments

I bet you're missing something, as that shouldn't raise a KeyError. How did you implement this?
Do you want to see the whole stuff?
You have problems with your code e.g. stateChurchDict[item] = {} will replace the Counter object with a normal dictionary. That initial for loop will no longer be needed. And the dictionary updates also. You should probably give a look to the links for defaultdict and Counter
1

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].

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.