John F.
John F.

Reputation: 67

2d dictionary in python

I'm having trouble creating a 2d dictionary. I have searched this website as well has numerous others and cannot find anything to help me with my issue!

I need to create a 2d dictionary that sorts data based on two distinguishing factors, animal and breed. The data is imported from a csv file. I start off sorting each line of the file into a 2d list where each entry is data for one animal/breed combination.

    for line in file:
        entries = line.split(',')
        list.append(entries)

This part works fine and gives me a well-organized list. My problem arises when trying to sort this list into a 2d dictionary based using animal and breed names as the types. So mydict['animal']['breed'] would give me a list of stats about the animal and breed combination. mydict['cat'] would list out all the breeds associated with cats and the list values mapped to each. My problem is I can only get one breed for every mydict['animal']. Here is an example of one of my attempts. I'm trying to do this without importing any supplementary dictionaries.

    for i in range(0, len(list)):
        #animal type is first element of the list
        key = list[i][0]
        #breed is second element of the list
        breed = list[i][1]
        animal_dict.set_default(key, {})[breed] = list[i][2:]
    print(animal_dict['cat'])

when I run this I get:

{'Siamese': ['15 years', 'No', 'Yes', '165']}

This is the very last breed entry for cats in the file, so my dictionary is overriding every breed entry as it loops through the list. Any suggestions on how to fix this? Sorry for the ambiguity in parts of this - I can only explain so much without the actual input file to reference.

Upvotes: 0

Views: 3103

Answers (1)

Jeremy Weirich
Jeremy Weirich

Reputation: 387

Short answer

This line is writing over your old data:

animal_dict.set_default(key, {})[breed] = list[i][2:]

Use append instead of an assignment here. You'll need to create an empty list to append to first.

Long answer

It's not very Pythonic to make an index and then use it to loop through the list - just go through the elements of the list directly! Let's call your list animals and your output dict animal_dict:

animal_dict= {}
for animal in animals:
    species = animal[0]
    breed = animal[1]
    stats = animal[2:]

This isn't the slickest way to do it, but it's simple. Now, we need to make sure we have the species in the dictionary. A simple way to do it is:

if species not in poke_dict:
    animal_dict[species] = {}

Now we check if breed is in this dictionary. If not, we make it:

if breed not in animal_dict[species]:
    animal_dict[species][breed] = []

Finally, now that we're sure our dict has the correct animal and breed keys, we can add our new entry with append:

animal_dict[species][breed].append(stats)

Putting it together, with some test values:

animals = [
    ['cat', 'Siamese', '15 years', 'No', 'Yes', '165'],
    ['cat', 'Bombay', '15 years', 'No', 'Yes', '165'],
    ['dog', 'Labrador', '15 years', 'No', 'Yes', '165'],
    ['cat', 'Siamese', '15 years', 'No', 'Yes', '165'],
    ['dog', 'Poodle', '15 years', 'No', 'Yes', '165'],
]

animal_dict= {}
for animal in animals:
    species = animal[0]
    breed = animal[1]
    stats = animal[2:]
    if species not in animal_dict:
        animal_dict[species] = {}
    if breed not in animal_dict[species]:
        animal_dict[species][breed] = []
    animal_dict[species][breed].append(stats)
print animal_dict['cat']

The construction

if species not in animal_dict:
    animal_dict[species] = {}
if breed not in animal_dict[species]:
    animal_dict[species][breed] = []

is clumsy, and can be replaced with setdefault like this:

animal_dict= {}
for animal in animals:
    species, breed, stats = animal[0], animal[1], animal[2:]
    animal_dict.setdefault(species, {}).setdefault(breed, []).append(stats)
print animal_dict['cat']

If there's only one instance of each animal/breed combination:

animal_dict = {}
for animal in animals:
    species, breed, stats = animal[0], animal[1], animal[2:]
    animal_dict.setdefault(species, {}).setdefault(breed, stats)
print animal_dict['cat']['Bombay']

Output:

{'Siamese': [
   ['15 years', 'No', 'Yes', '165'], 
   ['15 years', 'No', 'Yes', '165']
], 
'Bombay': [
   ['15 years', 'No', 'Yes', '165']
]}

Upvotes: 1

Related Questions