1

I´m having some trouble itering dictionaries within a list.

I have a list that looks like this:

mylist[0]

{'_id': ObjectId('aleatoryID'),
 'created_at': datetime.datetime(2018, 3, 22, 11, 58, 23, 585000),
 'person': {'id': '00115500',
  'scores': {'SCORE_3': {'@score': '45'}, 'SCORE_1': 205, 'SCORE_2': 487}}}

Itering through SCORE_1 and SCORE_2 is fine, my problem is SCORE_3 since it contains a sub-sctructure within it. Here is my attempt:

persons = []
for document in mylist:
    persons.append((document['person'].get('id'),
                    document['created_at'],
                    document['person']['scores'].get('SCORE_1'),
                    document['person']['scores'].get('SCORE_2'),
                    document['person']['scores']['SCORE_3'].get('@score')
                   ))

KeyError: 'SCORE_3'

What is the correct way to iter the dictionary in this situation?

Pablo Brenner
  • 183
  • 1
  • 1
  • 10
  • Possible duplicate of [What is the difference between dict.items() and dict.iteritems()?](https://stackoverflow.com/questions/10458437/what-is-the-difference-between-dict-items-and-dict-iteritems) – Raf May 25 '18 at 13:28
  • @Raf Sorry, but how is that related to this question? – Aran-Fey May 25 '18 at 13:29
  • Yes I did, just edited it, thanks Thomas. – Pablo Brenner May 25 '18 at 13:30
  • fyi, `.get()`, the way you use it, does the exact same thing as `[]`, you can just do `document['person']['scores']['SCORE_3']['@score']` instead. – Arne May 25 '18 at 13:30
  • @Arne this attempt returns KeyError: 'SCORE_3' – Pablo Brenner May 25 '18 at 13:35
  • 1
    Then you have some entry in your list that does not contain a `'SCORE_3'` in the `scores` dubdict. Print the documents before the `persons.append` line and look at the last one that appears. – Arne May 25 '18 at 13:44
  • @Arne that is correct, in some entries SCORE_3 does not exist – Pablo Brenner May 25 '18 at 13:48
  • @PabloBrenner how do you want to handle those cases? Insert a default value instead, not include the value, or skip cases where no `'SCORE_3'` is present? – Arne May 25 '18 at 13:57
  • @Arne inserting a default value would be the appropriate. – Pablo Brenner May 25 '18 at 14:01

2 Answers2

1

Based on your example this should work:

document['person']['scores'].get('SCORE_3')['@score']

Or just index without using get:

document['person']['scores']['SCORE_3']['@score']
Toby Petty
  • 4,431
  • 1
  • 17
  • 29
1

You have some entries in your subdictionary that do not exist. There are a number of approaches on how to handle this, choose whichever one suits your needs best:

# base case
for document in mylist:
    persons.append((document['person'].get('id'),
                    document['created_at'],
                    document['person']['scores'].get('SCORE_1'),
                    document['person']['scores'].get('SCORE_2'),
                    # the line below causes the trouble
                    document['person']['scores']['SCORE_3'].get('@score') 
                   ))

# 1 Include a default value

# a tad more tricky than just calling `get`, since you want to work with the
# potential result. Substitute the `None` with the default value of your choice
... document['person']['scores'].get('SCORE_3', {}).get('@score', None)

# 2 Skip such cases

try:
    persons.append((document['person'].get('id'),
                    document['created_at'],
                    document['person']['scores']['SCORE_1'],
                    document['person']['scores']['SCORE_2'],
                    document['person']['scores']['SCORE_3']['@score'])
                   ))
except KeyError:
    pass

# 3 Don't skip the case, just the field

# couldn't find a way that didn't include 5 `try...except`s or doing approach #1 
# and then filtering `None`s with [x for x in #1 if x is not None]. So I guess 
# default values > skipping fields.
Arne
  • 17,706
  • 5
  • 83
  • 99