hylaeus
hylaeus

Reputation: 255

more on creating dictionaries of dictionaries

I am a novice and learning about dictionaries in python, and spent better part of a day wrapping my head around it, I would appreciate some help!

I would like to create a dictionary of dictionaries:

data = [['dog', 'a'], ['mouse', 'a'], ['dog', 'b'], ['mouse', 'c'], ['dog', 'c']]
animals = ['dog', 'mouse']

I would like to do this:

final = {'dog': {'a': 0, 'b': 0, 'c': 0}, 'mouse':{'a': 0, 'c': 0} }

So far I have this code, which obviously is not working:

animal_dict = {}
for d in data:
    animal_dict[d[0]] = {}

letter_dict = {}
for animal in animal_dict:
    for d in data:
        if d[0] == animal:
            letter_dict[d[1]] = 0
            animal_dict[animal] = letter_dict

print animal_dict

Notice that it is adding an extra key ('b') in the 'mouse' dictionary. I know I am making it more complicated than it should be! Thanks in advance for helping a novice.

Upvotes: 2

Views: 130

Answers (6)

Blender
Blender

Reputation: 298216

You only really need one loop:

data = [['dog', 'a'], ['mouse', 'a'], ['dog', 'b'], ['mouse', 'c'], ['dog', 'c']]
animals = {}

for animal, letter in data:
    animals.setdefault(animal, {})[letter] = 0

Or if you don't like setdefault:

for animal, letter in data:
    if animal in animals:
        animals[animal][letter] = 0
    else:
        animals[animal] = {letter: 0}

Or with defaultdict:

from collections import defaultdict:

animals = defaultdict(dict) # creates a dict when the key doesn't exist

for animal, letter in data:
    animals.[animal][letter] = 0

Upvotes: 4

David Pullar
David Pullar

Reputation: 706

Quick and dirty, the animals list is unnecessary really.

d = {}
for animal, letter in data:
    if not d.has_key(animal):
        d[animal] = {}
    if not d[animal].has_key(letter):
        d[animal][letter] = 0

Upvotes: 0

Steve
Steve

Reputation: 716

Don't you love how many different ways there are to do things in Python? :-)

You can also just move creation of letter_dict inside the outer loop:

for animal in animal_dict:
    letter_dict = {}    # Create new letter_dict for each animal
    for d in data:
        if d[0] == animal:
            letter_dict[d[1]] = 0
            animal_dict[animal] = letter_dict

Upvotes: 0

sean
sean

Reputation: 3985

You are using the same dict when adding it to the animal_dict hence why there is an extra b key. You should check if the animal in animal_dict and if it isn't then add the new key with a empty dict.

for animal in animal_dict:
    if not animal in animal_dict:
        animal_dict[animal] = {}

    for d in data:
        if d[0] == animal:
            animal_dict[animal][d[1]] = letter_dict

Another option is to use a defaultdict documentation. That would remove the need for the key check in the loop.

Upvotes: 0

TerryA
TerryA

Reputation: 59984

>>> d = {}
>>> for i in data:
...     if i[0] not in d:
...             d[i[0]] = {i[1] : 0}
...     else:
...             d[i[0]][i[1]] = 0
... 
>>> d
{'mouse': {'a': 0, 'c': 0}, 'dog': {'a': 0, 'c': 0, 'b': 0}}

You're using the same dictionary to put both the dog and mouse values in, hence the extra 'b' key, because there would already be a 'b' from the dog. You could create an if/else statement to differentiate each.

Upvotes: 0

grc
grc

Reputation: 23575

You are setting both animal_dict['dog'] and animal_dict['mouse'] to the same letter_dict object. Any keys you add to one will be added to the other.

You do not actually need letter_dict. Try this instead:

for animal in animal_dict:
    for d in data:
        if d[0] == animal:
            animal_dict[animal][d[1]] = 0

Upvotes: 1

Related Questions