Dividing dictionary into nested dictionaries, based on the key's name on Python 3.4

I have the following dictionary (short version, real data is much larger):

dict = {'C-STD-B&M-SUM:-1': 0, 'C-STD-B&M-SUM:-10': 4.520475, 'H-NSW-BAC-ART:-9': 0.33784000000000003, 'H-NSW-BAC-ART:0': 0, 'H-NSW-BAC-ENG:-59': 0.020309999999999998, 'H-NSW-BAC-ENG:-6': 0,}

I want to divide it into smaller nested dictionaries, depending on a part of the key name.

Expected output would be:

# fixed closing brackets
dict1 = {'C-STD-B&M-SUM: {'-1': 0, '-10': 4.520475}}
dict2 = {'H-NSW-BAC-ART: {'-9': 0.33784000000000003, '0': 0}}
dict3 = {'H-NSW-BAC-ENG: {'-59': 0.020309999999999998, '-6': 0}}

Logic behind is:

dict1: if the part of the key name is 'C-STD-B&M-SUM', add to dict1.
dict2: if the part of the key name is 'H-NSW-BAC-ART', add to dict2.
dict3: if the part of the key name is 'H-NSW-BAC-ENG', add to dict3.

Partial code so far:

def divide_dictionaries(dict):
    c_std_bem_sum = {}
    for k, v in dict.items():
        if k[0:13] == 'C-STD-B&M-SUM':
            c_std_bem_sum = k[14:17], v

What I'm trying to do is to create the nested dictionaries that I need and then I'll create the dictionary and add the nested one to it, but I'm not sure if it's a good way to do it.

When I run the code above, the variable c_std_bem_sum becomes a tuple, with only two values that are changed at each iteration. How can I make it be a dictionary, so I can later create another dictionary, and use this one as the value for one of the keys?

Upvotes: 0

Views: 361

Answers (2)

Alex Huszagh
Alex Huszagh

Reputation: 14614

That's because you're setting your dictionary and overriding it with a tuple:

>>> a = 1, 2
>>> print a
>>> (1,2)

Now for your example:

 >>> def divide_dictionaries(dict):
 >>>      c_std_bem_sum = {}
 >>>      for k, v in dict.items():
 >>>          if k[0:13] == 'C-STD-B&M-SUM':
 >>>              new_key = k[14:17]         # sure you don't want [14:], open ended?
 >>>              c_std_bem_sum[new_key] = v

Basically, this grabs the rest of the key (or 3 characters, as you have it, the [14:None] or [14:] would get the rest of the string) and then uses that as the new key for the dict.

Upvotes: 0

DSM
DSM

Reputation: 353099

One way to approach it would be to do something like

d = {'C-STD-B&M-SUM:-1': 0, 'C-STD-B&M-SUM:-10': 4.520475, 'H-NSW-BAC-ART:-9': 0.33784000000000003, 'H-NSW-BAC-ART:0': 0, 'H-NSW-BAC-ENG:-59': 0.020309999999999998, 'H-NSW-BAC-ENG:-6': 0,}

def divide_dictionaries(somedict):
    out = {}
    for k,v in somedict.items():
        head, tail = k.split(":")
        subdict = out.setdefault(head, {})
        subdict[tail] = v
    return out

which gives

>>> dnew = divide_dictionaries(d)
>>> import pprint
>>> pprint.pprint(dnew)
{'C-STD-B&M-SUM': {'-1': 0, '-10': 4.520475},
 'H-NSW-BAC-ART': {'-9': 0.33784000000000003, '0': 0},
 'H-NSW-BAC-ENG': {'-59': 0.020309999999999998, '-6': 0}}

A few notes:

(1) We're using nested dictionaries instead of creating separate named dictionaries, which aren't convenient.

(2) We used setdefault, which is a handy way to say "give me the value in the dictionary, but if there isn't one, add this to the dictionary and return it instead.". Saves an if.

(3) We can use .split(":") instead of hardcoding the width, which isn't very robust -- at least assuming that's the delimiter, anyway!

(4) It's a bad idea to use dict, the name of a builtin type, as a variable name.

Upvotes: 1

Related Questions