Update dictionary key based on value - python

I have the following dictionary:
players = {'Roger': ['player1', 'dA'], 'Luka': ['player2', 'sK']}.
I want to update the key that contains 'player2', but
I can't update players[Luka] because 'player2' is not always Luka. How can I select keys linked to 'player2'?
(for those wondering, dA = Ace of Diamonds, sK = King of Spades. These values will also be different every time).
Edit:
Here's the part of my code: (It won't run because I left out a lot of clutter)
qPlayers = 2 #Amount of players
def game(qPlayers):
players[nr]["value"].append(new_card)
deal_to =[]
for player in players:
deal_to.append(player)
deal(qPlayers,deck,players,deal_to)
def setup(qPlayers):
playerhands = []
for x in range(1,qPlayers+1):
player = {}
player["name"] = input("Enter your name, player {}\n>>>".format(x))
playerhands.append(player)
return playerhands
def deal(qPlayers,deck,players,deal_to):
nr = -1
for player in deal_to:
nr +=1
new_card = getCard(deck) #getCard produces a random card like sA, k9, cQ

You can keep track of which key in the dict contains your player2 value, or else you will have to iterate through the dict until you find a key that does. If you frequently need to search based on something internal to the value, you may want to reconsider the data structure you are using to store this data.
def findKeyWithValue(value):
for playerName, playerData in players.items():
if value in playerData:
# your code here

You have two options here:
Search through the entire directory, checking for the value which contains 'player2'. This ends up being inefficient, and makes the dictionary structure somewhat useless.
Use a list instead of a dictionary, and model your data accordingly, similar to the example below.
An advantage of this data structure is that you don't need the redundant player1/player2 identifiers, since the list index provides that implicitly. To reference player2 you'd take the second element from the list (players[1] since indexing starts at 0).
players = [
{'Name' : 'Roger', 'Value' : 'dA'},
{'Name' : 'Luka', 'Value' : 'sK'}
]

You can iterate the dictionary to find the key to update. dict.iteritems() will do that job in python 2.7.
players = {'Roger': ['player1', 'dA'], 'Luka': ['player2', 'sK']}
for key, value in players.iteritems():
if value[0] == "player2":
players[key][1] = "sQ"
print players

Related

How do I add values sampled from a list to two nested dictionaries?

In this code block, I am trying to sample two values from a list and add them to a specific key/value pair in each of two nested dictionaries that share the same key/value structure. I have commented to clarify my intentions.
Here is the list of values to random sample from
gym_list = ['reddit.com','amazon.com','twitter.com','linkedin.com','ebay.com','netflix.com','stackoverflow.com','github.com','quora.com','google.com']
This is my attempt to create range of two key/values pairs in adjacent nested dictionaries
for i in range(poke_players[['player_1']['gyms_visited']],poke_players[['player_2']['gyms_visited']]):
if poke_players[['player_1']['gyms_visited']] : None; #If first key/value pair has no value
poke_players[['player_1']['gyms_visited']].append([sample(gym_list,2)]); #add random sample to first key/value pair
else:
poke_players[['player_2']['gyms_visited']] : None; #If second key/value pair has no value
poke_players[['player_1']['gyms_visited']].append([sample(gym_list,2)]): #add random sample to second key/value pair
return poke_players #return the updated dictionary
Your primary issue seems to be that you're not writing valid Python syntax.
I can see a couple of ways to go about the problem you describe. Let's first approach this as nested dictionaries, making one a defaultdict collection. This is not an exact implementation of your code but an approximation that shows how to create and manipulate the data structure:
from random import sample
from collections import defaultdict
gym_list = ['reddit.com', 'amazon.com', 'twitter.com', 'linkedin.com', 'ebay.com', 'netflix.com', 'stackoverflow.com', 'github.com', 'quora.com', 'google.com']
poke_players = defaultdict(dict)
def initialize_poke_players():
if 'gyms_visited' not in poke_players['player_1']: # If first key/value pair has no value
poke_players['player_1']['gyms_visited'] = sample(gym_list, 2) # add random sample to first key/value pair
if 'gyms_visited' not in poke_players['player_2']: # If second key/value pair has no value
poke_players['player_2']['gyms_visited'] = sample(gym_list, 2) # add random sample to second key/value pair
initialize_poke_players()
print("Player 1:", poke_players['player_1']['gyms_visited'])
print("Player 2:", poke_players['player_2']['gyms_visited'])
OUTPUT
> python3 test.py
Player 1: ['twitter.com', 'google.com']
Player 2: ['reddit.com', 'linkedin.com']
>
A simpler, single dictionary, approach is compound keys consisting of tuples of strings:
from random import sample
gym_list = ['reddit.com', 'amazon.com', 'twitter.com', 'linkedin.com', 'ebay.com', 'netflix.com', 'stackoverflow.com', 'github.com', 'quora.com', 'google.com']
poke_players = {}
def initialize_poke_players():
if ('player_1', 'gyms_visited') not in poke_players: # If first key/value pair has no value
poke_players[('player_1', 'gyms_visited')] = sample(gym_list, 2) # add random sample to first key/value pair
if ('player_2', 'gyms_visited') not in poke_players: # If second key/value pair has no value
poke_players[('player_2', 'gyms_visited')] = sample(gym_list, 2) # add random sample to second key/value pair
initialize_poke_players()
print("Player 1:", poke_players[('player_1', 'gyms_visited')])
print("Player 2:", poke_players[('player_2', 'gyms_visited')])

Adding to dictionary keys

I'm trying to create a running leaderboard in which each person starts with one point and I add to the key if they accomplish something. I'm not certain a dictionary is the best way to do it so recommendations are definitely welcomed.
I tried a list to begin with but a dictionary seemed to better suit my needs as I had lists inside of lists
myDict = {'person1' : 1 , 'person2' : 1 , 'person3' : 1}
If person1 were to do something i'd like their key to change to 2. I need to increment the keys, not assign a specific key. Also I will continually add entries to the dict for which I need their default value to be 1.
edit: Chris had a super helpful suggestion to use collections.defaultdict so that calling key that isn't in a dict adds it instead of returning a keyerror
A value can be added or changed or reassigned in a python dictionary by simply accessing through it's key
myDict[key] = value
In your case:
myDict["person1"] = 2 # Reassignment or changing
myDict["person1"] += 1 # Increementing
If the key doesn't exist, incrementing will be a problem. In that scenario, you need to check if the key is present or not.
if myDict["person5"]:
myDict["person5"] += 1
else:
myDict["person5"] = 1
Reference https://docs.python.org/3/tutorial/datastructures.html#dictionaries
Unless you want to do something like sorting players by scores at the end, a dictionary seems a good option. (You can do the sorting but have to have a workaround since dictionary is only indexed by its keys)
Otherwise you can do the following to update the scores
myDict = {}
person = '<person_name>'
# in case the person did something
if person in myDict:
myDict[person] += 1
else:
myDict[person] = 1
You can update a dictionary as follows:
>>> myDict = {'person1': 1, 'person2': 1}
>>> myDict['person7'] = 2
You may also want to investigate
import collections
myDict = collections.defaultdict(lambda: 1)
myDict['person7'] += 1
as this will automatically initialize unset values to 1 the first time they are read.

Python Max function - Finding highest value in a dictionary

My question is about finding highest value in a dictionary using max function.
I have a created dictionary that looks like this:
cc_GDP = {'af': 1243738953, 'as': 343435646, etc}
I would like to be able to simply find and print the highest GDP value for each country.
My best attempt having read through similar questions is as follows (I'm currently working through the Python crash course book at which the base of this code has been taken, note the get_country_code function is simply providing 2 letter abbreviations for the countries in the GDP_data json file):
#Load the data into a list
filename = 'gdp_data.json'
with open(filename) as f:
gdp_data = json.load(f)
cc_GDP` = {}
for gdp_dict in gdp_data:
if gdp_dict['Year'] == 2016:
country_name = gdp_dict['Country Name']
GDP_total = int(gdp_dict['Value'])
code = get_country_code(country_name)
if code:
cc_GDP[code] = int(GDP_total)
print(max(cc_GDP, key=lambda key: cc_GDP[key][1]))
This provides the following error 'TypeError: 'int' object is not subscriptable'
Note if leaving out the [1] in the print function, this does provide the highest key which relates to the highest value, but does not return the highest value itself which is what I wish to achieve.
Any help would be appreciated.
So you currently extract the key of the country that has the highest value with this line:
country_w_highest_val = max(cc_GDP, key=lambda key: cc_GDP[key]))
You can of course just look that up in the dictionary again:
highest_val = cc_GDP[contry_w_highest_val]
But simpler, disregard the keys completely, and just find the highest value of all values in the dictionary:
highest_val = max(cc_GDP.values())
How about something like this:
print max(cc_GDP.values())
That will give you the highest value but not the key.
The error is being cause because you need to look at the entire dictionary, not just one item. remove the [1] and then use the following line:
print(cc_GDP[max(cc_GDP, key=lambda key: cc_GDP[key])])
Your code currently just returns the dictionary key. You need to plug this key back into the dictionary to get the GDP.
You could deploy .items() method of dict to get key-value pairs (tuples) and process it following way:
cc_GDP = {'af': 1243738953, 'as': 343435646}
m = max(list(cc_GDP.items()), key=lambda x:x[1])
print(m) #prints ('af', 1243738953)
Output m in this case is 2-tuple, you might access key 'af' via m[0] and value 1243738953 via m[1].

Compare two separate dictionary values

I'm new to Python and looking to figure out how to code this properly. I have two lists of dictionaries and I'm trying to find if the student ID exists in a string that can contain the student ID and other information. My badly formed approach:
confirmed_students = [{'div_school_id': 'as-dh23d7ashdh'}, {'div_school_id': 'asdas-3sdfasd'}, {'div_school_id': 'i4-d9asjcg'}]
students = [{'student_id': 'dh23d7ashdh','name': 'First Last','student_grade': '4'}, {'student_id':'3sdfasd', 'name':...}]
bad_list = []
for student in students:
if student['student_id'] not in confirmed_students:
bad_list.append({"id": student['student_id'], "name": student['name'], "grade": student['student_grade']})
What would be the proper way to do this? Should I iterate through the list of dicts confirmed_students in the same loop? I only need to know if the student_id from the list of dicts called students exists at all in the list of dicts called confirmed_students and add the relevant info.
You can build the list using list comprehension:
bad_list = [{k: student[v] for k, v in zip(('id', 'name', 'grade'), ('student_id', 'name', 'student_grade'))} for student in students if student['student_id'] not in confirmed_students]
Sidenote: I suggest you define the students as a dictionary using the student_id as key (assuming it is unique, which it should). It will make it much more easier to perform comparisons like the one you want.
A brute force way of getting there (and probably not the most efficient) is to loop over both lists. Check if each element of students is in confirmed_students.
Firstly, you need a way of knowing if the student is in the confirmed_students list. There must be a key to match on. Looking at your data it seems as if confirmed_students has div_school_id that is some kind of composite of the student_id and some prefix.
# looking at one confirmed student as an example
confirmed_student = confirmed_students[0]
# confirmed_student = {'div_school_id': 'as-dh23d7ashdh'}
# we need to split the id on the '-' and keep the last part
confirmed_student_id = confirmed_student['div_school_id'].split("-")[1]
# gives us confirmed_student_id as 'dh23d7ashdh' which looks right?
# now we loop over your students and see if their id is in confirmed_students
bad_list = []
for student in students:
for confirmed_student in confirmed_students:
confirmed_student_id = confirmed_student['div_school_id'].split("-")[1]
if student["student_id"] == confirmed_student_id:
bad_list.append({"id": student['student_id'], "name": student['name'], "grade": student.get('student_grade', '')})
# break from the inner loop and continue the outer loop
# because we only need the first match
break

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 where I'm lost, as the keys are supposed to be the letters A‐Z and the values are sets of country names. I tried using a for loop, which I've commented on below, where the issue lies.
If the user enters a string with only one letter (like A), the program should print all the countries that begin with that letter. When you run the program, however, it only prints out one country for each letter.
The text file contains 228 lines. ie:
1:Qatar:98900
2:Liechtenstein:89400
3:Luxembourg:80600
4:Bermuda:69900
5:Singapore:59700
6:Jersey:57000
etc.
And here's my code.
initials = []
countries=[]
incomes=[]
dictionary={}
dictionary_2={}
keywordFile = open("raw.txt", "r")
for line in keywordFile:
line = line.upper()
line = line.strip("\n")
line = line.split(":")
initials.append(line[1][0]) # first letter of second element
countries.append(line[1])
incomes.append(line[2])
for i in range(0,len(countries)):
dictionary[countries[i]] = incomes[i]
this for loop should spit out 248 values (one for each country), where the key is the initial and the value is the country name. However, it only spits out 26 values (one country for each letter in the alphabet)
for i in range(0,len(countries)):
dictionary_2[initials[i]] = countries[i]
print(dictionary_2)
while True:
inputS = str(input('Enter an initial or a country name.'))
if inputS in dictionary:
value = dictionary.get(inputS, "")
print("The per capita income of {} is {}.".format((inputS.title()), value ))
elif inputS in dictionary_2:
value = dictionary_2.get(inputS)
print("The countries that begin with the letter {} are: {}.".format(inputS, (value.title())))
elif inputS.lower() in "quit":
break
else:
print("Does not exit.")
print("End of session.")
I'd appreciate any input leading me in the right direction.
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 in dict:
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 python3
from 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 in enumerate(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
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)
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)
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 import groupby
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]) }
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 in open('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).

Categories