Home > Enterprise >  Applying keys sequentially to a dict from a list
Applying keys sequentially to a dict from a list

Time:01-23

I'm scraping a website, which returns a dictionary:

person = {'name0':{'first0': 'John', 'last0':'Smith'},
          'age0':'10',
          'location0':{'city0':'Dublin'}
         }

I'm trying to write a function that will return a dictionary {'name':'John', 'age':'10'} when passed the above dictionary.

I want to ideally put a try:... except KeyError around each item since sometimes keys will be missing.

def func(person):
    filters = [('age', 'age0'), ('name', ['name0', 'first0'])]
    result = {'name': None, 'age': None}
    for i in filters:
        try:
            result[i[0]] = person[i[1]]
        except KeyError:
            pass
    return result

The problem is result[i[0]] = person[i[1]] doesn't work for 'name' since there's two keys that need to be followed sequentially and I don't know how to do that.

I want some way of telling it (in the loop) to go to person['name0']['first0'] (and so on to whatever depth the thing I want is).

I have lots of things to extract, so I'd rather do it in a loop instead of a try..except statement for each variable individually.

CodePudding user response:

In order to follow several key sequentially, you can use get and set the default value to {} (empty dictionary) for the upper levels. Set the default value to None (or whatever suits you) for the last level:

def func(person):
    return {'name': person.get('name0', {}).get('first0', None),
            'age': person.get('age0', None)}

CodePudding user response:

Best I could manage was using a for loop to iterate through the keys:

person = {'name0':{'first0': 'John', 'last0':'Smith'},
          'age0':'10',
          'location0':{'city0':'Dublin'}
         }

Additionally I used .get(key) rather than try..except as suggested by @wiwi


def func(person):
    filters = [('age', ['age0']), ('name', ['name0', 'first0'])]
    result = {'name': None, 'age': None}
    for filter in filters:
        temp = person.copy()
        for key in filter[1]:
            temp = temp.get(key)
            if not temp: # NoneType doesn't have .get method
                break
        result[filter[0]] = temp
    return result

func(person) then returns {'name': 'John', 'age': '10'}.

It handles missing input too:

person2 = {'age0':'10',
          'location0':{'city0':'Dublin'}}

func(person2) returns {'name': None, 'age': '10'}

  • Related