Skip to content Skip to sidebar Skip to footer

How To Create A Dictionary Whose Values Are Sets?

I'm working on an exercise that requires me to build two dictionaries, one whose keys are country names, and the values are the GDP. This part works fine. The second dictionary is

Solution 1:

Use defaultdict to make sure each value of your initials dict is a set, and then use the add method. If you just use = you'll be overwriting the initial keys value each time, defaultdict is an easier way of using an expression like:

if initial indict:
    dict[initial].add(country)
else:
    dict[initial] = {country}

See the full working example below, and also note that i'm using enumerate instead of range(0,len(countries)), which i'd also recommend:

#!/usr/bin/env python3from collections import defaultdict

initials, countries, incomes = [],[],[]

dict1 = {}
dict2 = defaultdict(set)

keywordFile = """
1:Qatar:98900

2:Liechtenstein:89400

3:Luxembourg:80600

4:Bermuda:69900

5:Singapore:59700

6:Jersey:57000
""".split("\n\n")

for line in keywordFile:
    line = line.upper().strip("\n").split(":")
    initials.append(line[1][0])
    countries.append(line[1])
    incomes.append(line[2])

for i,country inenumerate(countries):
    dict1[country] = incomes[i]
    dict2[initials[i]].add(country)

print(dict2["L"])

Result:

{'LUXEMBOURG', 'LIECHTENSTEIN'}

see: https://docs.python.org/3/library/collections.html#collections.defaultdict

Solution 2:

The values for dictionary2 should be such that they can contain a list of countries. One option is to use a list as the values in your dictionary. In your code, you are overwriting the values for each key whenever a new country with the same initial is to be added as the value.

Moreover, you can use the setdefault method of the dictionary type. This code:

dictionary2 = {}
for country in countries:
    dictionary2.setdefault(country[0], []).append(country)

should be enough to create the second dictionary elegantly.

setdefault, either returns the value for the key (in this case the key is set to the first letter of the country name) if it already exists, or inserts a new key (again, the first letter of the country) into the dictionary with a value that is an empty set [].

edit

if you want your values to be set (for faster lookup/membership test), you can use the following lines:

dictionary2 = {}
for country in countries:
    dictionary2.setdefault(country[0], set()).add(country)

Solution 3:

Here's a link to a live functioning version of the OP's code online.

The keys in Python dict objects are unique. There can only ever be one 'L' key a single dict. What happens in your code is that first the key/value pair 'L':'Liechtenstein' is inserted into dictionary_2. However, in a subsequent iteration of the for loop, 'L':'Liechtenstein' is overwritten by 'L':Luxembourg. This kind of overwriting is sometimes referred to as "clobbering".

Fix

One way to get the result that you seem to be after would be to rewrite that for loop:

for i in range(0,len(countries)):
    dictionary_2[initials[i]] = dictionary_2.get(initials[i], set()) | {countries[i]}
    print(dictionary_2)

Also, you have to rewrite the related elif statement beneath that:

elif inputS in dictionary_2:
    titles = ', '.join([v.title() for v in dictionary_2[inputS]])
    print("The countries that begin with the letter {} are: {}.".format(inputS, titles))

Explanation

Here's a complete explanation of the dictionary_2[initials[i]] = dictionary_2.get(initials[i], set()) | {countries[i]} line above:

  • dictionary_2.get(initials[i], set())

    • If initials[i] is a key in dictionary_2, this will return the associated value. If initials[i] is not in the dictionary, it will return the empty set set() instead.
  • {countries[i]}

    • This creates a new set with a single member in it, countries[i].
  • dictionary_2.get(initials[i], set()) | {countries[i]}
    • The | operator adds all of the members of two sets together and returns the result.
  • dictionary_2[initials[i]] = ...
    • The right hand side of the line either creates a new set, or adds to an existing one. This bit of code assigns that newly created/expanded set back to dictionary_2.

Notes

The above code sets the values of dictionary_2 as sets. If you want to use list values, use this version of the for loop instead:

for i in range(0,len(countries)):
    dictionary_2[initials[i]] = dictionary_2.get(initials[i], []) + [countries[i]]
    print(dictionary_2)

Solution 4:

You're very close to what you're looking for, You could populate your dictionaries respectively while looping over the contents of the file raw.txt that you're reading. You can also read the contents of the file first and then perform the necessary operations to populate the dictionaries. You could achieve your requirement with nice oneliners in python using dict comprehensions and groupby. Here's an example:

country_per_capita_dict = {}
letter_countries_dict = {}
keywordFile = [line.strip() for line in open('raw.txt' ,'r').readlines()]

You now have a list of all lines in the keywordFile as follows:

['1:Qatar:98900', '2:Liechtenstein:89400', '3:Luxembourg:80600', '4:Bermuda:69900', '5:Singapore:59700', '6:Jersey:57000', '7:Libya:1000', '8:Sri Lanka:5000']

As you loop over the items, you can split(':') and use the [1] and [2] index values as required.

You could use dictionary comprehension as follows:

country_per_capita_dict = {entry.split(':')[1] : entry.split(':')[2] for entry in keywordFile}

Which results in:

{'Qatar': '98900', 'Libya': '1000', 'Singapore': '59700', 'Luxembourg': '80600', 'Liechtenstein': '89400', 'Bermuda': '69900', 'Jersey': '57000'}

Similarly using groupby from itertools you can obtain:

from itertools importgroupbycountry_list= country_per_capita_dict.keys()
country_list.sort()
letter_countries_dict = {k: list(g) for k,g in groupby(country_list, key=lambda x:x[0]) }

Which results in the required dictionary of initial : [list of countries]

{'Q': ['Qatar'], 'S': ['Singapore'], 'B': ['Bermuda'], 'L': ['Luxembourg', 'Liechtenstein'], 'J': ['Jersey']}

A complete example is as follows:

from itertools import groupby

country_per_capita_dict = {}
letter_countries_dict = {}
keywordFile = [line.strip() for line inopen('raw.txt' ,'r').readlines()]

country_per_capita_dict = {entry.split(':')[1] : entry.split(':')[2] for entry in keywordFile}
country_list = country_per_capita_dict.keys()
country_list.sort()
letter_countries_dict = {k: list(g) for k,g in groupby(country_list, key=lambda x:x[0]) }

print (country_per_capita_dict)
print (letter_countries_dict)

Explanation:

The line:

country_per_capita_dict = {entry.split(':')[1] : entry.split(':')[2] for entry in keywordFile}

loops over the following list ['1:Qatar:98900', '2:Liechtenstein:89400', '3:Luxembourg:80600', '4:Bermuda:69900', '5:Singapore:59700', '6:Jersey:57000', '7:Libya:1000', '8:Sri Lanka:5000'] and splits each entry in the list by :

It then takes the value at index [1] and [2] which are the country names and the per capita value and makes them into a dictionary.

country_list = country_per_capita_dict.keys()
country_list.sort()

This line, extracts the name of all the countries from the dictionary created before into a list and sorts them alphabetically for groupby to work correctly.

letter_countries_dict = {k: list(g) for k,g in groupby(country_list, key=lambda x:x[0]) }

This lambda expression takes the input as the list of countries and groups together the names of countries where each x starts with x[0] into list(g).

Post a Comment for "How To Create A Dictionary Whose Values Are Sets?"