Complex dictionaries in python

How to make a dictionary of dictionaries with lists inside?
For example we have a number of stellar spectral types (spec) and for each one of them we have a series of spectral lines (line) and their equivalent widths (ew). By creating a rather complex dictionary we can then call the list of values for the equivalent width for any spectral type and line we want.

Let’s look at this step by step.

1. A simple dictionary, with spetral types (spec) as keys and corresponding spectral lines as values:
dic = {}
dic[spec] = line

Output (which includes all spectral types but only the last spectral line parsed, because it just overrides the value for each key):
{'B1': 'HeI/4026', 'B0.5': 'HeI/4026'}

2. In order to get all spectral lines we have to make a list of values for each key. For this we have to import defaultdict first:

from collections import defaultdict
dic = defaultdict(list)

defaultdict(, {'B1': ['CaIIK/3928', 'HeI/4009', 'HeI/4026'], 'B0.5': ['CaIIK/3928', 'HeI/4009', 'HeI/4026']})

3. Now, we want to add the value of ew for each line.

from collections import defaultdict
dic = defaultdict(defaultdict)
dic[spec][line] = ew

defaultdict(, {'B1': defaultdict(None, {'HeI/4009': 0.38, 'CaIIK/3928': 0.29, 'HeI/4026': 1.03}), 'B0.5': defaultdict(None, {'HeI/4009': 0.33, 'CaIIK/3928': 0.27, 'HeI/4026': 1.09})})

4. If we want to have not only a value but a list of values (per spectral line) we need to define a function within the defaultdict. If we just put defaultdict(defaultdict(list)) it will not work as the defaultdict(list) will return something that is not expected as input by the next level defaultdict. To overcome this we use a “lambda” (anonymous) function:

from collections import defaultdict
dic = defaultdict(lambda: defaultdict(list))

defaultdict( at 0x2508578>, {'B1': defaultdict(, {'HeI/4009': [0.38], 'CaIIK/3928': [0.29], 'HeI/4026': [1.03]}), 'B0.5': defaultdict(, {'HeI/4009': [0.33, 0.63], 'CaIIK/3928': [0.27, 0.13], 'HeI/4026': [1.09, 1.96]})})

We can easily call any spectral line per type by simply calling dic[specific_spec][specific_line], e.g. dic[‘B0.5’][‘CaIIK/3928’] will give us [0.27, 0.13].

Leave a Reply

Your email address will not be published. Required fields are marked *