In a programming course I am now at dictionaries point in python. So I have this task in which I need to add a "fail" command, which basically is printing out students if a grade is less than 4. I have googled it and searched for similar problems in here, but just couldn't find a similar example. Hope you can help me. Also, I have added the code and in "def fail():" you can see what was my idea. But there is an error code with this - ValueError: too many values to unpack (expected 2). PS, I'm new to python.
students = {('Ozols', 'Jānis'): {'Math': '10', 'ProgVal': '5', 'Sports': '5'},
('Krumiņa', 'Ilze'): {'Math': '7', 'ProgVal': '3', 'Sports': '6'},
('Liepa', 'Peteris'): {'Math': '3', 'ProgVal': '7', 'Sports': '7'},
('Lapsa', 'Maris'): {'Math': '10', 'ProgVal': '10', 'Sports': '3'}}
courses = ['Math', 'ProgVal', 'Sports']
def fail():
for lName, fName in students.keys():
for course, grade in students.values():
if grade < 4:
print(fName, lName)
while True:
print()
command = input("command:> ")
command = command.lower()
if command == 'fail':
fail()
elif command == 'done':
break
print("DONE")
There're a few issues with your code.
Firstly, you should be using an integer (int) or float to store a student's score. You can fix it by changing them to integers:
students = {('Ozols', 'Jānis'): {'Math': 10, 'ProgVal': 5, 'Sports': 5},
('Krumiņa', 'Ilze'): {'Math': 7, 'ProgVal': 3, 'Sports': 6},
('Liepa', 'Peteris'): {'Math': 3, 'ProgVal': 7, 'Sports': 7},
('Lapsa', 'Maris'): {'Math': 10, 'ProgVal': 10, 'Sports': 3}}
Secondly, you should not be using a loop of students.values() within a loop of students.keys() as it will loop through the entire dictionary again - you want to loop through each subject of the values (which are dictionaries of scores) of each student, which is stored in the list called students.
Try this:
students = {('Ozols', 'Jānis'): {'Math': 10, 'ProgVal': 5, 'Sports': 5},
('Krumiņa', 'Ilze'): {'Math': 7, 'ProgVal': 3, 'Sports': 6},
('Liepa', 'Peteris'): {'Math': 3, 'ProgVal': 7, 'Sports': 7},
('Lapsa', 'Maris'): {'Math': 10, 'ProgVal': 10, 'Sports': 3}}
courses = ['Math', 'ProgVal', 'Sports']
for lName, fName in students.keys():
studentRecord = students[(lName, fName)]
for course in studentRecord:
if studentRecord[course] < 4:
print(fName, lName, course)
Try the below
students = {
('Ozols', 'Jānis'): {
'Math': '10',
'ProgVal': '5',
'Sports': '5'
},
('Krumiņa', 'Ilze'): {
'Math': '7',
'ProgVal': '3',
'Sports': '6'
},
('Liepa', 'Peteris'): {
'Math': '3',
'ProgVal': '7',
'Sports': '7'
},
('Lapsa', 'Maris'): {
'Math': '10',
'ProgVal': '10',
'Sports': '3'
}
}
courses = ['Math', 'ProgVal', 'Sports']
def fail():
for k,v in students.items():
for course, grade in v.items():
if int(grade) < 4:
print(f'{k[0]} {k[1]} failed in {course}')
fail()
output
Krumiņa Ilze failed in ProgVal
Liepa Peteris failed in Math
Lapsa Maris failed in Sports
I'm writing a Python script. I need to return lines that contain latest 'timestamp': field from a text file. For example, in the below text file example:
{'uid': 3167, 'user_id': '6', 'timestamp': datetime.datetime(2021, 3, 10, 18, 7, 13), 'status': 1, 'punch': 1}, {'uid': 3168, 'user_id': '198', 'timestamp': datetime.datetime(2021, 3, 10, 18, 10, 42), 'status': 2, 'punch': 1}, {'uid': 3169, 'user_id': '3', 'timestamp': datetime.datetime(2021, 3, 10, 18, 13, 53), 'status': 1, 'punch': 1}, {'uid': 3170, 'user_id': '13', 'timestamp': datetime.datetime(2021, 3, 10, 18, 22, 2), 'status': 1, 'punch': 1}, {'uid': 3171, 'user_id': '9', 'timestamp': datetime.datetime(2021, 3, 10, 18, 22, 43), 'status': 1, 'punch': 1}, {'uid': 3172, 'user_id': '15', 'timestamp': datetime.datetime(2021, 3, 10, 18, 32, 30), 'status': 2, 'punch': 1}, {'uid': 3173, 'user_id': '4', 'timestamp': datetime.datetime(2021, 3, 10, 19, 42, 26), 'status': 1, 'punch': 1}, {'uid': 3174, 'user_id': '1', 'timestamp': datetime.datetime(2021, 3, 10, 19, 42, 34), 'status': 1, 'punch': 1}, {'uid': 3175, 'user_id': '3', 'timestamp': datetime.datetime(2021, 3, 11, 8, 48, 6), 'status': 1, 'punch': 1}, {'uid': 3176, 'user_id': '7', 'timestamp': datetime.datetime(2021, 3, 11, 9, 2, 30), 'status': 2, 'punch': 1}, {'uid': 3177, 'user_id': '5', 'timestamp': datetime.datetime(2021, 3, 11, 9, 12, 40), 'status': 1, 'punch': 1}, {'uid': 3178, 'user_id': '6', 'timestamp': datetime.datetime(2021, 3, 11, 9, 40, 47), 'status': 1, 'punch': 1}, {'uid': 3179, 'user_id': '15', 'timestamp': datetime.datetime(2021, 3, 11, 9, 49, 59), 'status': 2, 'punch': 1},
Return Text File 'today's date 11/3/2021' ex:
{'uid': 3175, 'user_id': '3', 'timestamp': datetime.datetime(2021, 3, 11, 8, 48, 6), 'status': 1, 'punch': 1}, {'uid': 3176, 'user_id': '7', 'timestamp': datetime.datetime(2021, 3, 11, 9, 2, 30), 'status': 2, 'punch': 1}, {'uid': 3177, 'user_id': '5', 'timestamp': datetime.datetime(2021, 3, 11, 9, 12, 40), 'status': 1, 'punch': 1}, {'uid': 3178, 'user_id': '6', 'timestamp': datetime.datetime(2021, 3, 11, 9, 40, 47), 'status': 1, 'punch': 1}, {'uid': 3179, 'user_id': '15', 'timestamp': datetime.datetime(2021, 3, 11, 9, 49, 59), 'status': 2, 'punch': 1},
It seems you're dealing with tabular data and pandas is very natural for that.
import datetime
import pandas as pd
df = pd.DataFrame([{'uid': 3167, 'user_id': '6', 'timestamp': datetime.datetime(2021, 3, 10, 18, 7, 13), 'status': 1, 'punch': 1}, {'uid': 3168, 'user_id': '198', 'timestamp': datetime.datetime(2021, 3, 10, 18, 10, 42), 'status': 2, 'punch': 1}, {'uid': 3169, 'user_id': '3', 'timestamp': datetime.datetime(2021, 3, 10, 18, 13, 53), 'status': 1, 'punch': 1}, {'uid': 3170, 'user_id': '13', 'timestamp': datetime.datetime(2021, 3, 10, 18, 22, 2), 'status': 1, 'punch': 1}, {'uid': 3171, 'user_id': '9', 'timestamp': datetime.datetime(2021, 3, 10, 18, 22, 43), 'status': 1, 'punch': 1}, {'uid': 3172, 'user_id': '15', 'timestamp': datetime.datetime(2021, 3, 10, 18, 32, 30), 'status': 2, 'punch': 1}, {'uid': 3173, 'user_id': '4', 'timestamp': datetime.datetime(2021, 3, 10, 19, 42, 26), 'status': 1, 'punch': 1}, {'uid': 3174, 'user_id': '1', 'timestamp': datetime.datetime(2021, 3, 10, 19, 42, 34), 'status': 1, 'punch': 1}, {'uid': 3175, 'user_id': '3', 'timestamp': datetime.datetime(2021, 3, 11, 8, 48, 6), 'status': 1, 'punch': 1}, {'uid': 3176, 'user_id': '7', 'timestamp': datetime.datetime(2021, 3, 11, 9, 2, 30), 'status': 2, 'punch': 1}, {'uid': 3177, 'user_id': '5', 'timestamp': datetime.datetime(2021, 3, 11, 9, 12, 40), 'status': 1, 'punch': 1}, {'uid': 3178, 'user_id': '6', 'timestamp': datetime.datetime(2021, 3, 11, 9, 40, 47), 'status': 1, 'punch': 1}, {'uid': 3179, 'user_id': '15', 'timestamp': datetime.datetime(2021, 3, 11, 9, 49, 59), 'status': 2, 'punch': 1},])
today = pd.to_datetime('today').normalize()
rows = df[df['timestamp'] >= today]
Which gives
uid user_id timestamp status punch
8 3175 3 2021-03-11 08:48:06 1 1
9 3176 7 2021-03-11 09:02:30 2 1
10 3177 5 2021-03-11 09:12:40 1 1
11 3178 6 2021-03-11 09:40:47 1 1
12 3179 15 2021-03-11 09:49:59 2 1
If you want the result in a list of dicts, you can then do rows.to_dict('records').
Without pandas it'd be a similar approach of getting today's datetime and iterating over your data to filter them.
lines = [{'uid': 3167, 'user_id': '6', 'timestamp': datetime.datetime(2021, 3, 10, 18, 7, 13), 'status': 1, 'punch': 1}, {'uid': 3168, 'user_id': '198', 'timestamp': datetime.datetime(2021, 3, 10, 18, 10, 42), 'status': 2, 'punch': 1}, {'uid': 3169, 'user_id': '3', 'timestamp': datetime.datetime(2021, 3, 10, 18, 13, 53), 'status': 1, 'punch': 1}, {'uid': 3170, 'user_id': '13', 'timestamp': datetime.datetime(2021, 3, 10, 18, 22, 2), 'status': 1, 'punch': 1}, {'uid': 3171, 'user_id': '9', 'timestamp': datetime.datetime(2021, 3, 10, 18, 22, 43), 'status': 1, 'punch': 1}, {'uid': 3172, 'user_id': '15', 'timestamp': datetime.datetime(2021, 3, 10, 18, 32, 30), 'status': 2, 'punch': 1}, {'uid': 3173, 'user_id': '4', 'timestamp': datetime.datetime(2021, 3, 10, 19, 42, 26), 'status': 1, 'punch': 1}, {'uid': 3174, 'user_id': '1', 'timestamp': datetime.datetime(2021, 3, 10, 19, 42, 34), 'status': 1, 'punch': 1}, {'uid': 3175, 'user_id': '3', 'timestamp': datetime.datetime(2021, 3, 11, 8, 48, 6), 'status': 1, 'punch': 1}, {'uid': 3176, 'user_id': '7', 'timestamp': datetime.datetime(2021, 3, 11, 9, 2, 30), 'status': 2, 'punch': 1}, {'uid': 3177, 'user_id': '5', 'timestamp': datetime.datetime(2021, 3, 11, 9, 12, 40), 'status': 1, 'punch': 1}, {'uid': 3178, 'user_id': '6', 'timestamp': datetime.datetime(2021, 3, 11, 9, 40, 47), 'status': 1, 'punch': 1}, {'uid': 3179, 'user_id': '15', 'timestamp': datetime.datetime(2021, 3, 11, 9, 49, 59), 'status': 2, 'punch': 1},]
today = datetime.date.today()
today = datetime.datetime(today.year, today.month, today.day)
result = [line for line in lines if line['timestamp'] >= today]
I have this :
[
[{ 'position': 1, 'user_id': 2, 'value': 4, 'points': 100}],
[{ 'position': 2, 'user_id': 6, 'value': 3, 'points': 88}],
[{ 'position': 3, 'user_id': 5, 'value': 2, 'points': 77}],
[{ 'position': 4, 'user_id': 7, 'value': 1, 'points': 66}],
[{ 'position': 5, 'user_id': 3, 'value': 1, 'points': 9}],
[{ 'position': 6, 'user_id': 11, 'value': 0, 'points': 9}],
[{ 'position': 7, 'user_id': 1, 'value': 0, 'points': 3}],
[{ 'position': 8, 'user_id': 10, 'value': 0, 'points': 3}],
[{ 'position': 9, 'user_id': 4, 'value': 0, 'points': 2}],
[{ 'position': 10, 'user_id': 8, 'value': 0, 'points': 2}]
]
is organized by points.
The idea is to choose the user_id and generate a new list with the selected 5 users.
Example:
user_id=3:
[{ 'position': 3, 'user_id': 5, 'value': 2, 'points': 77}],
[{ 'position': 4, 'user_id': 7, 'value': 1, 'points': 66}],
[{ 'position': 5, 'user_id': 3, 'value': 1, 'points': 9}],
[{ 'position': 6, 'user_id': 11, 'value': 0, 'points': 9}],
[{ 'position': 7, 'user_id': 1, 'value': 0, 'points': 3}]
It returns user_id 3 in the middle with 2 users hight and 2 users lower
user_id=2
[{ 'position': 1, 'user_id': 2, 'value': 4, 'points': 100}],
[{ 'position': 2, 'user_id': 6, 'value': 3, 'points': 88}],
[{ 'position': 3, 'user_id': 5, 'value': 2, 'points': 77}],
[{ 'position': 4, 'user_id': 7, 'value': 1, 'points': 66}],
[{ 'position': 5, 'user_id': 3, 'value': 1, 'points': 9}],
As user_id hasn't higher users it returns 4 lower users. So is always same logic.
user_id=9:
[{ 'position': 6, 'user_id': 11, 'value': 0, 'points': 9}],
[{ 'position': 7, 'user_id': 1, 'value': 0, 'points': 3}],
[{ 'position': 8, 'user_id': 10, 'value': 0, 'points': 3}],
[{ 'position': 9, 'user_id': 4, 'value': 0, 'points': 2}],
[{ 'position': 10, 'user_id': 8, 'value': 0, 'points': 2}]
on user_id=9 We only have 1 user lower so we add 3 higher users
If for example we just have 2 users in list, it should return that 2 users.
Main rules:
If we have 5 users or more, as to return 5 users.
if we have 4 users, as to return 4 users
How is a good way to do it?
thanks
This is basically only an update of my answer to your original question.
a = [
[{ 'position': 1, 'user_id': 2, 'value': 4, 'points': 100}],
[{ 'position': 2, 'user_id': 6, 'value': 3, 'points': 88}],
[{ 'position': 3, 'user_id': 5, 'value': 2, 'points': 77}],
[{ 'position': 4, 'user_id': 7, 'value': 1, 'points': 66}],
[{ 'position': 5, 'user_id': 3, 'value': 1, 'points': 9}],
[{ 'position': 6, 'user_id': 11, 'value': 0, 'points': 9}],
[{ 'position': 7, 'user_id': 1, 'value': 0, 'points': 3}],
[{ 'position': 8, 'user_id': 10, 'value': 0, 'points': 3}],
[{ 'position': 9, 'user_id': 4, 'value': 0, 'points': 2}],
[{ 'position': 10, 'user_id': 8, 'value': 0, 'points': 2}]
]
# Sort it if not already sorted
# a.sort(key=lambda x: x[0]['position'])
def find_index(l, user_id):
i = 0
while l[i][0]['user_id'] != user_id:
i += 1
return i
def get_subset(l, i):
return l[:(i + 1 + max(2, 4 - i))][-5:]
get_subset(a, find_index(a, 3))
Taking this dictionary:
{'local': {'count': 7,
'dining-and-nightlife': {'count': 1,
'bar-clubs': {'count': 1}
},
'activities-events': {'count': 6,
'outdoor-adventures': {'count': 4},
'life-skill-classes': {'count': 2}
}
}}
How do I determine the most relevant match (within a 30% leeway)? For example, activities-events has a count of 6 so 6/7 = 85% and its child outdoor-adventures has a count of 4 out 6 (66%). So from this the most relevant category is outdoor-adventures.
In this example:
{'local': {'count': 11,
'dining-and-nightlife': {'count': 4,
'bar-clubs': {'count': 4}
},
'activities-events': {'count': 6,
'outdoor-adventures': {'count': 4},
'life-skill-classes': {'count': 2}
}
}}
Take both dining-and-nightlife (33%) with bar-clubs (100%) and activities-events (54%) with
outdoor-aventures (66%).
I was hoping the percentage cutoff to be determined by
cutoff = 0.3
The idea here is to determine which category is most relevant removing the smaller results (below a 30%) match.
#F.J answered this question below but now I wish to update the counts in the tree.
Inital Output:
{'local': {'activities-events': {'count': 6,
'life-skill-classes': {'count': 2},
'outdoor-adventures': {'count': 4}},
'count': 11,
'dining-and-nightlife': {'bar-clubs': {'count': 4}, 'count': 4}}}
Post output:
{'local': {'activities-events': {'count': 6,
'life-skill-classes': {'count': 2},
'outdoor-adventures': {'count': 4}},
'count': 10,
'dining-and-nightlife': {'bar-clubs': {'count': 4}, 'count': 4}}}
The following should work, note that this will modify your input dictionary in place:
def keep_most_relevant(d, cutoff=0.3):
for k, v in list(d.items()):
if k == 'count':
continue
if 'count' in d and v['count'] < d['count'] * cutoff:
del d[k]
else:
keep_most_relevant(v)
Examples:
>>> d1 = {'local': {'count': 7, 'dining-and-nightlife': {'count': 1, 'bar-clubs': {'count': 1}}, 'activities-events': {'count': 6, 'outdoor-adventures': {'count': 4}, 'life-skill-classes': {'count': 2}}}}
>>> keep_most_relevant(d1)
>>> pprint.pprint(d1)
{'local': {'activities-events': {'count': 6,
'life-skill-classes': {'count': 2},
'outdoor-adventures': {'count': 4}},
'count': 7}}
>>> d2 = {'local': {'count': 11, 'dining-and-nightlife': {'count': 4, 'bar-clubs': {'count': 4}}, 'activities-events': {'count': 6, 'outdoor-adventures': {'count': 4}, 'life-skill-classes': {'count': 2}}}}
>>> keep_most_relevant(d2)
>>> pprint.pprint(d2)
{'local': {'activities-events': {'count': 6,
'life-skill-classes': {'count': 2},
'outdoor-adventures': {'count': 4}},
'count': 11,
'dining-and-nightlife': {'bar-clubs': {'count': 4}, 'count': 4}}}
def matches(match, cutoff):
total = float(match['count'])
for k in match:
if k == 'count':
continue
score = match[k]['count'] / total
if score >= cutoff:
yield (k, score)
m = list(matches(match[k], cutoff))
if m: yield max(m, key=lambda (c, s): s)
def best_matches(d, cutoff):
for k in d:
for m in matches(d[k], cutoff):
yield m
Test 1
>>> d = {'local': {'count': 7,
'dining-and-nightlife': {'count': 1,
'bar-clubs': {'count': 1}
},
'activities-events': {'count': 6,
'outdoor-adventures': {'count': 4},
'life-skill-classes': {'count': 2}
}
}}
>>> print list(best_matches(d, 0.3))
[('activities-events', 0.8571428571428571), ('outdoor-adventures', 0.66666666666666663)]
Test 2
>>> d = {'local': {'count': 11,
'dining-and-nightlife': {'count': 4,
'bar-clubs': {'count': 4}
},
'activities-events': {'count': 6,
'outdoor-adventures': {'count': 4},
'life-skill-classes': {'count': 2}
}
}}
>>> print list(best_matches(d, 0.3))
[('dining-and-nightlife', 0.36363636363636365), ('bar-clubs', 1.0), ('activities-events', 0.54545454545454541), ('outdoor-adventures', 0.66666666666666663)]