Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create nested dictionary on the fly in Python

Trying to understand how to create nested dictionaries on the fly. Ideally my dictionary would look something like:

mydict = { 'Message 114861156': { 'email': ['[email protected]', '[email protected]'] }, { 'status': 'Queued mail for delivery' }} 

Here's what i have so far:

sampledata = "Message 114861156 to [email protected] [email protected]  [InternalId=260927844] Queued mail for delivery'."

makedict(sampledata)

def makedict(results):
  newdict = {}
  for item in results:
    msgid = re.search(r'Message \d+', item)
    msgid = msgid.group()
    newdict[msgid]['emails'] = re.findall(r'\w+@\w+\.\w+', item)
    newdict[msgid]['status'] = re.findall(r'Queued mail for delivery', item)

has the following output:

Traceback (most recent call last):
  File "wildfires.py", line 57, in <module>
    striptheshit(q_result)
  File "wildfires.py", line 47, in striptheshit
    newdict[msgid]['emails'] = re.findall(r'\w+@\w+\.\w+', item)
KeyError: 'Message 114861156'

How do you make a nested dictionary like this on the fly?

like image 693
dobbs Avatar asked Feb 19 '16 20:02

dobbs


People also ask

Can you create nested dictionary in Python?

In Python, a Nested dictionary can be created by placing the comma-separated dictionaries enclosed within braces.

How do you create a nested dictionary from a list Python?

To create a nested dictionary, simply pass dictionary key:value pair as keyword arguments to dict() Constructor. You can use dict() function along with the zip() function, to combine separate lists of keys and values obtained dynamically at runtime.

Can you create a dictionary from a list in Python?

You can convert a Python list to a dictionary using the dict. fromkeys() method, a dictionary comprehension, or the zip() method. The zip() method is useful if you want to merge two lists into a dictionary.

Can dictionaries be nested?

A dictionary can contain dictionaries, this is called nested dictionaries.


2 Answers

dict.setdefault is a good tool, so is collections.defaultdict

Your problem right now is that newdict is an empty dictionary, so newdict[msgid] refers to a non-existent key. This works when assigning things (newdict[msgid] = "foo"), however since newdict[msgid] isn't set to anything originally, when you try to index it you get a KeyError.

dict.setdefault lets you sidestep that by initially saying "If msgid exists in newdict, give me its value. If not, set its value to {} and give me that instead.

def makedict(results):
    newdict = {}
    for item in results:
        msgid = re.search(r'Message \d+', item).group()
        newdict.setdefault(msgid, {})['emails'] = ...
        newdict[msgid]['status'] = ...
        # Now you KNOW that newdict[msgid] is there, 'cuz you just created it if not!

Using collections.defaultdict saves you the step of calling dict.setdefault. A defaultdict is initialized with a function to call that produces a container that any non-existent key gets assigned as a value, e.g.

from collections import defaultdict

foo = defaultdict(list)
# foo is now a dictionary object whose every new key is `list()`
foo["bar"].append(1)  # foo["bar"] becomes a list when it's called, so we can append immediately

You can use this to say "Hey if I talk to you about a new msgid, I want it to be a new dictionary.

from collections import defaultdict

def makedict(results):
    newdict = defaultdict(dict)
    for item in results:
        msgid = re.search(r'Message \d+', item).group()
        newdict[msgid]['emails'] = ...
        newdict[msgid]['status'] = ...
like image 70
Adam Smith Avatar answered Oct 22 '22 16:10

Adam Smith


Found what I was looking for in this regard at https://quanttype.net/posts/2016-03-29-defaultdicts-all-the-way-down.html

def fix(f):
    return lambda *args, **kwargs: f(fix(f), *args, **kwargs)

>>> from collections import defaultdict
>>> d = fix(defaultdict)()
>>> d["a"]["b"]["c"]
defaultdict(<function <lambda> at 0x105c4bed8>, {})
like image 38
sampson Avatar answered Oct 22 '22 17:10

sampson