Skip to content

S3Q1 · Book Reading List Data Analysis

⚡ Quick Reference

Function: book_analysis(data: list, request: str)

def book_analysis(data: list, request: str):
    n     = len(data)
    avg_r = sum(b["rating"] for b in data) / n
    avg_p = sum(b["pages"]  for b in data) / n

    if request == "average_rating":
        return round(avg_r, 2)

    if request == "average_pages":
        return round(avg_p, 2)

    if request == "longest_book":
        return max(data, key=lambda b: (b["pages"], b["rating"]))["book_id"]

    if request == "above_average_books":
        return {b["book_id"] for b in data
                if b["rating"] > avg_r and b["pages"] > avg_p}

Key rules: - Compute both averages upfront - reused by longest_book and above_average_books - longest_book ties → highest rating wins (tuple key) - above_average_books uses strict > for both conditions - returns a set


Problem Statement

Problem

Implement book_analysis(data, request) - four analytics operations on a list of book dicts.

Sample data:

data = [
    {"book_id": "B1", "pages": 320, "rating": 4.5},
    {"book_id": "B2", "pages": 150, "rating": 3.8},
    {"book_id": "B3", "pages": 480, "rating": 4.2},
    {"book_id": "B4", "pages": 480, "rating": 4.7},
    {"book_id": "B5", "pages": 200, "rating": 4.9},
]


Operation 1 - average_rating

return round(sum(b["rating"] for b in data) / len(data), 2)

From sample: (4.5+3.8+4.2+4.7+4.9) / 5 = 22.1/5 = 4.42


Operation 2 - average_pages

return round(sum(b["pages"] for b in data) / len(data), 2)

From sample: (320+150+480+480+200) / 5 = 1630/5 = 326.0


Operation 3 - longest_book

Highest page count; ties broken by highest rating:

return max(data, key=lambda b: (b["pages"], b["rating"]))["book_id"]

From sample: B3 and B4 both have 480 pages. B4 rating=4.7 > B3 rating=4.2 → "B4"


Operation 4 - above_average_books

Books with rating > avg_rating AND pages > avg_pages (strict):

avg_r = sum(b["rating"] for b in data) / len(data)   # 4.42
avg_p = sum(b["pages"]  for b in data) / len(data)   # 326.0

return {b["book_id"] for b in data
        if b["rating"] > avg_r and b["pages"] > avg_p}

From sample: - B1: rating 4.5 > 4.42 ✅, pages 320 > 326 ❌ - B2: rating 3.8 > 4.42 ❌ - B3: rating 4.2 > 4.42 ❌ - B4: rating 4.7 > 4.42 ✅, pages 480 > 326 ✅ → included - B5: rating 4.9 > 4.42 ✅, pages 200 > 326 ❌

Result: {"B4"}


Complete solution approaches

def book_analysis(data: list, request: str):
    n     = len(data)
    avg_r = sum(b["rating"] for b in data) / n
    avg_p = sum(b["pages"]  for b in data) / n

    if request == "average_rating":
        return round(avg_r, 2)

    if request == "average_pages":
        return round(avg_p, 2)

    if request == "longest_book":
        return max(data, key=lambda b: (b["pages"], b["rating"]))["book_id"]

    if request == "above_average_books":
        return {b["book_id"] for b in data
                if b["rating"] > avg_r and b["pages"] > avg_p}
def book_analysis(data: list, request: str):
    n = len(data)

    if request == "average_rating":
        return round(sum(b["rating"] for b in data) / n, 2)

    if request == "average_pages":
        return round(sum(b["pages"] for b in data) / n, 2)

    if request == "longest_book":
        best = data[0]
        for b in data[1:]:
            if b["pages"] > best["pages"]:
                best = b
            elif b["pages"] == best["pages"] and b["rating"] > best["rating"]:
                best = b
        return best["book_id"]

    if request == "above_average_books":
        avg_r = sum(b["rating"] for b in data) / n
        avg_p = sum(b["pages"]  for b in data) / n
        return {b["book_id"] for b in data
                if b["rating"] > avg_r and b["pages"] > avg_p}
def book_analysis(data: list, request: str):
    n     = len(data)
    avg_r = sum(b["rating"] for b in data) / n
    avg_p = sum(b["pages"]  for b in data) / n

    ops = {
        "average_rating":     lambda: round(avg_r, 2),
        "average_pages":      lambda: round(avg_p, 2),
        "longest_book":       lambda: max(data, key=lambda b: (b["pages"], b["rating"]))["book_id"],
        "above_average_books":lambda: {b["book_id"] for b in data
                                        if b["rating"] > avg_r and b["pages"] > avg_p},
    }
    return ops[request]()

Key takeaways

01

Compute averages upfront - three tasks need them

avg_r and avg_p are used by both average_rating, average_pages, and above_average_books. Computing them once at the top avoids redundant scans and keeps each branch clean.

02

Tuple key for longest_book tie-breaking

key=lambda b: (b["pages"], b["rating"]) - max compares pages first; only when tied does rating decide. One max() call handles both criteria without extra logic.

03

above_average_books uses strict > and returns a set

Both conditions are strict greater-than - books exactly at the average are excluded. The return type is a set (use a set comprehension {...}), not a list.