I'm trying to programmatically set a values to each item in a list inside a nested dictionary.
for example, let's say my initial dictionary, which I constructed is:
{'Abraham': {'subjects': ['Chem', 'Bio', 'Phy', 'Math']}}
Given some lists of values:
assess_type = ['Quiz', 'HW', 'ATTND', 'Exam']
chem = ['127', '135', '17', '46']
bio = ['154', '64', '14', '54']
phy = ['115', '115', '15', '55']
math = ['140', '160', '20', '40']
And I want to achieve a result like this:
{'Abraham': {'subjects': [
'Chem': {'Quiz': '127', 'HW': '135', 'ATTND': '17', 'Exam': '46'},
'Bio': {'Quiz': '154', 'HW': '64', 'ATTND': '14', 'Exam': '54'} ,
'Phy': {'Quiz': '115', 'HW': '115', 'ATTND': '15', 'Exam': '55'},
'Math': {'Quiz': '140', 'HW': '160', 'ATTND': '20', 'Exam': '40'}
]}}
I can construct the dictionary itself, but where I am having issues is how to set the values programmatically. how do I index into the list inside the dictionary and set the value like that programmatically if I just have a list of values as written above?
CodePudding user response:
You can use dict(zip(keys, values) to create the dictionary based on the given list:
assess_type = ['Quiz', 'HW', 'ATTND', 'Exam']
chem = ['127', '135', '17', '46']
then for chem will be chem = dict(zip(assess_type, chem))
the result will be {'Quiz': '127', 'HW': '135', 'ATTND': '17', 'Exam': '46'}
CodePudding user response:
First, let's fix your final example, your list is built like a dictionary and will not work.
You can either add the course name to the nested dictionary:
{'Abraham': {'subjects': [
{'course': 'Chem', 'Quiz': '127', 'HW': '135', 'ATTND': '17', 'Exam': '46'},
{'course': 'Bio', 'Quiz': '154', 'HW': '64', 'ATTND': '14', 'Exam': '54'} ,
{'course': 'Phy', 'Quiz': '115', 'HW': '115', 'ATTND': '15', 'Exam': '55'},
{'course': 'Math', 'Quiz': '140', 'HW': '160', 'ATTND': '20', 'Exam': '40'}
]}}
Which is kind of clunky, and you'd have to check the course for each list index.
Or you could just replace that list with curly braces and make it a nested dictionary which, to me, makes more sense. I just don't know if you have a particular requirement the makes the list necessary:
{'Abraham': {'subjects': {
'Chem': {'Quiz': '127', 'HW': '135', 'ATTND': '17', 'Exam': '46'},
'Bio': {'Quiz': '154', 'HW': '64', 'ATTND': '14', 'Exam': '54'} ,
'Phy': {'Quiz': '115', 'HW': '115', 'ATTND': '15', 'Exam': '55'},
'Math': {'Quiz': '140', 'HW': '160', 'ATTND': '20', 'Exam': '40'}
}}}
Let's say we assigned my examples to a variable called "student".
You would access student named Abraham similarly to a list index, but with the name of the key instead. student['Abraham']
. You would do the same for nested lists and dictionaries, either using a key or index number.
In my first example, student['Abraham']['subjects'][0]['HW']
would give you the homework score for Abraham in Chemisty.
In my second example, student['Abraham']['subjects']['Chem']['HW']
would give you the same result.
You could also assign values the same way as accessing them:
student['Abraham']['subjects']['Chem']['HW'] = 105
And if you insisted on using a list, you would need to fix it to something like my first example, and instead of using 'Chem' for the key, you would have to pick the appropriate index.
One more thing, if you mistype a key while assigning a value to a dictionary item, you could end up adding a new key and duplicate information. If I wanted to change the homework score and accidentally typed:
student['Abraham']['subjects']['Chem']['HHW'] = 107
Your nested dictionary for Abraham would now contain 2 keys, HW with a value of 105 and HHW with a value of 107. Just something to keep in mind.
CodePudding user response:
First thing is to make data aligned to each other like this
if 'subjects': ['Chem', 'Bio', 'Phy', 'Math']
strings are in the Title case then the variables carrying the values should be in the Title case to make it comparable during using eval()
function below
let's say we have student
student = {"Abraham": {"subjects": ["Chem", "Bio", "Phy", "Math"]}}
Then we have assessment type
assess_type = ["Quiz", "HW", "ATTND", "Exam"]
These are the values that should be zipped to each subject in assess_type order
Chem = ["127", "135", "17", "46"]
Bio = ["154", "64", "14", "54"]
Phy = ["115", "115", "15", "55"]
Math = ["140", "160", "20", "40"]
Now we will loop through the student dict and then subjects
for key, value in student.items():
# Loops through the dictionary and gets the values
for sub in value["subjects"]:
# Loops through the list of subjects and gets the values of the subjects in the list of subjects
student[key][sub] = dict(
zip(assess_type, eval(sub))
) # Enzips the list of subjects and the list of values
Then if we print the student:
{'Abraham': {'subjects': ['Chem', 'Bio', 'Phy', 'Math'], 'Chem': {'Quiz': '127', 'HW': '135', 'ATTND': '17', 'Exam': '46'}, 'Bio': {'Quiz': '154', 'HW': '64', 'ATTND': '14', 'Exam': '54'}, 'Phy': {'Quiz': '115', 'HW': '115', 'ATTND': '15', 'Exam': '55'}, 'Math': {'Quiz': '140', 'HW': '160', 'ATTND': '20', 'Exam': '40'}}}
Now you will be able to modify the output structure after that with a little effort.
So, in the loop, The eval()
method parses the expression passed to this method and runs the python expression (code) within the program.
The zip()
function takes iterables (can be zero or more), aggregates them in a tuple, and returns it.
For better understanding please google these terms to get an idea whats is happening in the loop.