goldisfine
goldisfine

Reputation: 4850

Why is the key identified as the value?

I'm using a comprehension to create a dictionary. The error indicates that my key is stored as the value rather than the key.

Here is the full situation:

I have BLS data that looks like this:

O*NET-SOC Code  Element ID  Element Name    Scale ID    Data Value  N   Standard Error  Lower CI Bound  Upper CI Bound  Recommend Suppress  Not Relevant    Date    Domain Source
11-1011.00  1.A.1.a.1   Oral Comprehension  IM  4.5 8   0.19    4.13    4.87    N   n/a Jun-06  Analyst
11-1011.00  1.A.1.a.1   Oral Comprehension  LV  4.75    8   0.25    4.26    5.24    N   N   Jun-06  Analyst
11-1011.00  1.A.1.a.2   Written Comprehension   IM  4.38    8   0.18    4.02    4.73    N   n/a Jun-06  Analyst

And would like to return a structure that looks like this, with detailed level data for every job (a job is represented by the SOC code, the left-most column of the data. For instance, the SOC code of the job 'clerk' below could be 11-1011.00).

{
    'job':'clerk', 'description': 'works in a bank', 'abilities': {
        'math': [
            {
            'Scale ID': 'IM',
            'Data Value': 4.5,
            'N' : 8,
            'S_E': 0.19
            },
            {'Scale ID': 'LV',
            'Data Value': 4.75,
            'N': 8,
            'S_E': 0.25
            }        
        ]
        'english': [
            {
            'Scale ID': 'IM',
            'Data Value': 2,
            'N' : 8,
            'S_E': 0.19
            },
            {'Scale ID': 'LV',
            'Data Value': 3,
            'N': 8,
            'S_E': 0.25
            }        
        ]  
    }
},

To do this, I create a list of dictionaries in my abilities field, and for each ability, create a list of the level (LV) and importance (IM) data.

The error is flagged when I'm creating the dictionary for the IM / LV dictionaries.

Here's my code:

"""
Abilities
"""

# returns a list of dictionaries, each of the dictionaries representing a row in the data posted above with keys = top row and values = row vals.
abilities_m_l = create_abilities_master_list(file_list[0])    

# for each job (for each dictionary in the master list of job dictionaries)
for job in d_l:

    job_row = 1

    while job_row < 100: # just to test

        # initialize the list of abilities for the job
        job['abilities'] = []
        job['abilities'].append({abilities_m_l[job_row]['Element Name']:[]}) 

        while job['O*NET-SOC Code'] == abilities_m_l[job_row]['O*NET-SOC Code']:

            if abilities_m_l[job_row]['Element Name'] == abilities_m_l[job_row-1]['Element Name']:
                job[abilities_m_l[job_row]['Element Name']].append({key:value for key,value in abilities_m_l[job_row] if key not in ('O*NET-SOC Code','Element Name', 'Scale ID')})

            else:
                job[abilities_m_l[job_row]['Element Name']] = []
                job[abilities_m_l[job_row]['Element Name']].append({key:value for key,value in abilities_m_l[job_row] if key not in ('O*NET-SOC Code','Element Name', 'Scale ID')})

            job_row += 1   

    break           

for job in d_l:
    print job['abilities']

Here is my error:

Traceback (most recent call last):
  File "/private/var/folders/jv/9_sy0bn10mbdft1bk9t14qz40000gn/T/Cleanup At Startup/bls-397147690.633.py", line 65, in <module>
    job[abilities_m_l[job_row]['Element Name']].append({key:value for key,value in abilities_m_l[job_row] if key not in ('O*NET-SOC Code','Element Name', 'Scale ID')})
KeyError: 'Oral Comprehension'
logout

Upvotes: 0

Views: 95

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1121864

You are testing for the presence of the list incorrectly:

if abilities_m_l[job_row]['Element Name'] == abilities_m_l[job_row-1]['Element Name']:
    job[abilities_m_l[job_row]['Element Name']].append({key:value for key,value in abilities_m_l[job_row] if key not in ('O*NET-SOC Code','Element Name', 'Scale ID')})

Here you assume that just because the previous row had the same element name, you will have already added a list for that key. Apparently that assumption is wrong for the Oral Comprehension key.

Just test for the key:

key = abilities_m_l[job_row]['Element Name']
if key not in job:
    job[key] = []
job[key].append({key:value for key,value in abilities_m_l[job_row] if key not in ('O*NET-SOC Code','Element Name', 'Scale ID')})

You can also use dict.setdefault() to have it return the list value, or set an empty list value if the key is not yet set:

key = abilities_m_l[job_row]['Element Name']
job.setdefault(key, []).append({key:value for key,value in abilities_m_l[job_row] if key not in ('O*NET-SOC Code','Element Name', 'Scale ID')})

Upvotes: 1

chander
chander

Reputation: 2167

You cannot use .append() append to a non-existent key.

Consider using collections.defaultdict (so that non-existent keys default to using a list for their value), or initializing abilities_m_l[job_row]['Element Name'], or 'job' with a list. One of them is trying to append to a non-existent key (if the key doesn't already exist, you get the KeyError back)

Start with:

from collections import defaultdict

job=defaultdict(list)

That will ensure that keys default to the empty list, and allow your code to work.

Upvotes: 1

Related Questions