I would like to compare nested dictionaries.
classes= {
"class1" : {
"name" : "Math",
"hour" : [4,5]
},
"class2" : {
"name" : "Bio",
"hour" : [3,4]
},
"class3" : {
"name" : "Chem",
"hour" : [5,6]
}
}
I need to know at which hour the classes overlap. So, the output would be something like this:
Math and Bio overlap at hour 4
Math and Chem overlap at hour 5
CodePudding user response:
You could make a data structure that works better for the kind od query you want. For example, making a dictionary with hour keys and a list of classes at these hours.
from collections import defaultdict
classes = {
"class1" : {
"name" : "Math",
"hour" : [4,5]
},
"class2" : {
"name" : "Bio",
"hour" : [3,4]
},
"class3" : {
"name" : "Chem",
"hour" : [5,6]
}
}
hours = defaultdict(list)
for c in classes.values():
for hour in c['hour']:
hours[hour].append(c['name'])
hours
will be a structure like:
{4: ['Math', 'Bio'], 5: ['Math', 'Chem'], 3: ['Bio'], 6: ['Chem']})
This will let you iterate over the hours and filter out those that don't have more than one class:
for hour, cs in hours.items():
if len(cs) > 1:
print(f"{' and '.join(cs)} overlap at hour {hour}")
Which prints:
Math and Bio overlap at hour 4
Math and Chem overlap at hour 5
On a side note, your dictionary classes should probably be a list like [{"name": "Math","hour": [4,5]}, {...}, ...]
. A good indication of this the numerically increasing keys without any semantic meaning: class1
, class2
etc.
CodePudding user response:
Assuming the structure of the dictionary will remain the same, i.e. the naming convention for the keys of the nested dictionaries will be "name"
and "hour"
for class name and class duration. Also, assuming that the two values in the "hour"
key of the nested dictionary are the starting and ending hours for the class, i.e. the range of the class, the problem could be solved in the two simple steps below.
First we define a function that returns a list of the hour overlaps between any two classes, taking two "hour"
keys from the nested dictionaries as input.
def get_overlap(l1:list, l2:list):
r1 = range(l1[0], l1[1] 1)
r2 = range(l2[0], l2[1] 1)
return [i for i in r1 if i in r2]
Now, we iterate over the main dictionary, comparing each key with the others only once., i.e. "class1"
with ["class2", "class3", "class4"]
, "class2"
with ["class3", "class4"]
, and "class3"
with ["class4"]
, etc. We do this with the following code:
for i, k1 in enumerate(classes):
for k2 in list(classes)[i 1:]:
ovlp = get_overlap(classes[k1]['hour'], classes[k2]['hour'])
if len(ovlp):
print(f"{classes[k1]['name']} and {classes[k2]['name']} overlap at hour(s) {ovlp}")
Now, taking a dictionary given below:
classes= {
"class1" : {
"name" : "Math",
"hour" : [4,5]
},
"class2" : {
"name" : "Bio",
"hour" : [3,4]
},
"class3" : {
"name" : "Chem",
"hour" : [5,6]
},
"class4" : {
"name" : "Phy",
"hour" : [4,6]
}
}
We get the output:
Math and Bio overlap at hour(s) [4]
Math and Chem overlap at hour(s) [5]
Math and Phy overlap at hour(s) [4, 5]
Bio and Phy overlap at hour(s) [4]
Chem and Phy overlap at hour(s) [5, 6]