S3Q1 · YouTube Video Engagement Analysis¶
⚡ Quick Reference
Five functions on a list of video dicts (title, views, likes, comments):
def total_engagement(video: dict) -> int:
return video["likes"] + video["comments"]
def engagement_rate(video: dict) -> float:
if video["views"] == 0:
return 0.0
return round((video["likes"] + video["comments"]) / video["views"] * 100, 2)
def most_engaging_video(videos: list) -> str:
return max(videos, key=lambda v: engagement_rate(v))["title"]
def videos_with_engagement_rate_above_threshold(videos: list, threshold: float) -> list:
return [v["title"] for v in videos if engagement_rate(v) > threshold]
def average_engagement_rate(videos: list) -> float:
active = [v for v in videos if v["views"] > 0]
return round(sum(engagement_rate(v) for v in active) / len(active), 2)
Key rules:
- engagement_rate → (likes + comments) / views * 100, rounded to 2 dp
- Zero views → return 0.0 (avoid division by zero)
- most_engaging_video → ties broken by first in list (max scans left to right)
- average_engagement_rate → excludes videos with zero views
Problem Statement¶
Problem
Implement five functions that analyse a list of YouTube video dictionaries, each with keys "title", "views", "likes", and "comments".
Sample data:
videos = [
{"title": "Python Tutorial", "views": 10000, "likes": 800, "comments": 200},
{"title": "Web Dev Crash", "views": 5000, "likes": 600, "comments": 100},
{"title": "Data Science 101", "views": 8000, "likes": 400, "comments": 50},
{"title": "AI for Beginners", "views": 0, "likes": 0, "comments": 0},
]
Function 1 -total_engagement¶
Simply sum likes and comments:
| Video | Likes | Comments | Total |
|---|---|---|---|
| Python Tutorial | 800 | 200 | 1000 |
| Web Dev Crash | 600 | 100 | 700 |
| Data Science 101 | 400 | 50 | 450 |
Function 2 -engagement_rate¶
def engagement_rate(video: dict) -> float:
if video["views"] == 0:
return 0.0
return round((video["likes"] + video["comments"]) / video["views"] * 100, 2)
| Video | Calculation | Rate |
|---|---|---|
| Python Tutorial | 1000 / 10000 * 100 |
10.0 |
| Web Dev Crash | 700 / 5000 * 100 |
14.0 |
| Data Science 101 | 450 / 8000 * 100 |
5.63 |
| AI for Beginners | views = 0 | 0.0 |
Function 3 -most_engaging_video¶
Return the title with the highest engagement rate. For ties, return the first one in the list.
def most_engaging_video(videos: list) -> str:
return max(videos, key=lambda v: engagement_rate(v))["title"]
max(videos, key=...) scans left to right and keeps the first maximum found -so ties are broken by position automatically.
For the sample data: Web Dev Crash has rate 14.0 -highest → "Web Dev Crash".
Function 4 -videos_with_engagement_rate_above_threshold¶
Return titles of videos with rate strictly greater than the threshold:
def videos_with_engagement_rate_above_threshold(videos: list, threshold: float) -> list:
return [v["title"] for v in videos if engagement_rate(v) > threshold]
For threshold = 10.0: Web Dev Crash (14.0 > 10.0) qualifies; Python Tutorial (10.0 = 10.0) does not (strict >).
Function 5 -average_engagement_rate¶
Average engagement rate of videos with non-zero views only:
def average_engagement_rate(videos: list) -> float:
active = [v for v in videos if v["views"] > 0]
return round(sum(engagement_rate(v) for v in active) / len(active), 2)
For the sample: exclude "AI for Beginners" (views=0). Average of [10.0, 14.0, 5.63] = 29.63 / 3 = 9.88.
Complete solution approaches¶
def total_engagement(video: dict) -> int:
return video["likes"] + video["comments"]
def engagement_rate(video: dict) -> float:
if video["views"] == 0:
return 0.0
return round((video["likes"] + video["comments"]) / video["views"] * 100, 2)
def most_engaging_video(videos: list) -> str:
return max(videos, key=lambda v: engagement_rate(v))["title"]
def videos_with_engagement_rate_above_threshold(videos: list, threshold: float) -> list:
return [v["title"] for v in videos if engagement_rate(v) > threshold]
def average_engagement_rate(videos: list) -> float:
active = [v for v in videos if v["views"] > 0]
return round(sum(engagement_rate(v) for v in active) / len(active), 2)
def total_engagement(video: dict) -> int:
return video["likes"] + video["comments"]
def engagement_rate(video: dict) -> float:
if video["views"] == 0:
return 0.0
rate = (video["likes"] + video["comments"]) / video["views"] * 100
return round(rate, 2)
def most_engaging_video(videos: list) -> str:
best = videos[0]
for v in videos[1:]:
if engagement_rate(v) > engagement_rate(best):
best = v
return best["title"]
def videos_with_engagement_rate_above_threshold(videos: list, threshold: float) -> list:
result = []
for v in videos:
if engagement_rate(v) > threshold:
result.append(v["title"])
return result
def average_engagement_rate(videos: list) -> float:
active = [v for v in videos if v["views"] > 0]
total = sum(engagement_rate(v) for v in active)
return round(total / len(active), 2)
def total_engagement(video: dict) -> int:
return video["likes"] + video["comments"]
def engagement_rate(video: dict) -> float:
if video["views"] == 0:
return 0.0
return round((video["likes"] + video["comments"]) / video["views"] * 100, 2)
def most_engaging_video(videos: list) -> str:
return max(videos, key=lambda v: engagement_rate(v))["title"]
def videos_with_engagement_rate_above_threshold(videos: list, threshold: float) -> list:
return list(map(
lambda v: v["title"],
filter(lambda v: engagement_rate(v) > threshold, videos)
))
def average_engagement_rate(videos: list) -> float:
active = list(filter(lambda v: v["views"] > 0, videos))
rates = list(map(engagement_rate, active))
return round(sum(rates) / len(rates), 2)
filter(lambda v: ..., videos) selects qualifying videos. map(lambda v: v["title"], ...) extracts titles. map(engagement_rate, active) computes all rates in one pass.
Key takeaways¶
max(iterable, key=lambda) for "highest by criterion"
max(videos, key=lambda v: engagement_rate(v)) finds the video with the highest rate. Tie-breaking is automatic -max returns the first maximum found scanning left to right.
Guard against zero views
Always check if views == 0: return 0.0 before dividing. Even if the problem says views are positive, defensive coding prevents ZeroDivisionError on edge cases.
Reuse engagement_rate in every function
Define engagement_rate once and call it in all other functions. Never rewrite the formula -if it changes, you only update one place.