EASYTUTORGUIDE

Practical tutorials, tools, courses, digital skills, and business promotion.

Free Learning

JavaScript – Chapter 2: Development Environment

Learn what JavaScript is, where it runs, why it is important, and how beginners can start using it with simple examples and clear output.

Beginner Friendly JavaScript Basics Web Development Code Examples
JavaScript Lesson 2 Chapter 2 Topics Day / Night Mode

Main reading content

python-course-chapter-30

Chapter 30: Comprehensions and Advanced Collection Processing

A complete beginner-friendly guide to list, set, dictionary, and generator comprehensions, including filtering, transforming, flattening, and processing collections efficiently.

Goal: Learn how to create and process Python collections with concise comprehensions while keeping code readable, efficient, and easy to maintain.

Chapter 30 Topics

30.1 Review of List Comprehensions

```

A list comprehension is a short way to create a new list from an existing iterable. It combines an expression, a loop, and sometimes a condition inside square brackets. The expression describes the value that should be placed into the new list.

List comprehensions are commonly used to transform numbers, clean text, select records, or create calculated values. They can replace several lines of loop-based code, but they should be used only when the result remains clear and easy to understand.

Basic Syntax

new_list = [expression for item in iterable]

Example

# Original list of numbers
```

numbers = [1, 2, 3, 4, 5]

# Create a new list containing the square of each number

squares = [number ** 2 for number in numbers]

print("Original numbers:", numbers)
print("Squared numbers:", squares)
```

Output

Original numbers: [1, 2, 3, 4, 5]
```

Squared numbers: [1, 4, 9, 16, 25]
```

Output Explanation

Python takes each value from numbers, calculates its square, and places the result into the new list. The original list is not changed.

Traditional Loop Version

numbers = [1, 2, 3, 4, 5]
```

squares = []

for number in numbers:
squares.append(number ** 2)

print(squares)
```

Output

[1, 4, 9, 16, 25]

Both versions produce the same result. The comprehension version is shorter, while the traditional loop may be easier for a new programmer to understand at first.

```

30.2 Conditional Comprehensions

```

A conditional comprehension can filter values or choose between different output values. A filtering condition is placed after the loop. Only items that satisfy the condition are included in the new collection.

A conditional expression is placed before the loop when every item should produce a result but the result depends on a condition. These two forms look similar but serve different purposes.

Filtering Syntax

new_list = [expression for item in iterable if condition]

Example: Keep Even Numbers

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
```

# Include only numbers that are evenly divisible by 2

even_numbers = [
number
for number in numbers
if number % 2 == 0
]

print(even_numbers)
```

Output

[2, 4, 6, 8]

Conditional Expression Syntax

new_list = [
value_if_true if condition else value_if_false
for item in iterable
```

]
```

Example: Label Numbers

numbers = [1, 2, 3, 4, 5]
```

labels = [
"Even" if number % 2 == 0 else "Odd"
for number in numbers
]

print(labels)
```

Output

['Odd', 'Even', 'Odd', 'Even', 'Odd']

Output Explanation

The first example removes all odd numbers. The second example keeps every number but converts each one into either the word Even or Odd.

```

30.3 Nested Comprehensions

```

A nested comprehension contains one comprehension inside another. It is often used for two-dimensional collections such as tables, grids, matrices, and lists containing other lists.

Nested comprehensions can be powerful, but they may become difficult to read. Beginners should first understand the equivalent nested loops before using a compact form.

Example: Create a Multiplication Grid

# Create three rows
```

# Each row contains four calculated values

grid = [
[row * column for column in range(1, 5)]
for row in range(1, 4)
]

print(grid)
```

Output

[[1, 2, 3, 4], [2, 4, 6, 8], [3, 6, 9, 12]]

Display Each Row Separately

grid = [
[row * column for column in range(1, 5)]
for row in range(1, 4)
```

]

for row in grid:
print(row)
```

Output

[1, 2, 3, 4]
```

[2, 4, 6, 8]
[3, 6, 9, 12]
```

Output Explanation

The outer comprehension creates each row. The inner comprehension creates the values inside that row. The first row multiplies by one, the second row multiplies by two, and the third row multiplies by three.

```

30.4 Set Comprehensions

```

A set comprehension creates a set instead of a list. It uses curly braces and produces unique values. Duplicate results are automatically removed because sets cannot contain repeated items.

Set comprehensions are useful when you need distinct values, such as unique categories, names, letters, file extensions, or calculated results. Sets are unordered, so their displayed order may differ.

Basic Syntax

new_set = {expression for item in iterable}

Example

words = [
"Python",
"python",
"JAVA",
"Java",
"HTML",
"html"
```

]

# Convert every word to lowercase

# Duplicate lowercase values are removed automatically

unique_languages = {
word.lower()
for word in words
}

print(unique_languages)
```

Example Output

{'python', 'java', 'html'}

Output Explanation

Each word is converted to lowercase. Because sets store only unique values, repeated versions of the same language are removed. The exact output order may be different.

Example with a Condition

numbers = [1, 2, 2, 3, 4, 4, 5, 6]
```

even_squares = {
number ** 2
for number in numbers
if number % 2 == 0
}

print(even_squares)
```

Example Output

{4, 16, 36}
```

30.5 Dictionary Comprehensions

```

A dictionary comprehension creates key-value pairs. It uses curly braces and places a colon between the key expression and the value expression. Each loop iteration produces one dictionary entry.

Dictionary comprehensions are useful for creating lookup tables, transforming existing dictionaries, reversing mappings, calculating values, or filtering records by key and value.

Basic Syntax

new_dictionary = {
key_expression: value_expression
for item in iterable
```

}
```

Example

numbers = [1, 2, 3, 4, 5]
```

# Use each number as a key

# Use its square as the value

square_table = {
number: number ** 2
for number in numbers
}

print(square_table)
```

Output

{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

Example: Transform an Existing Dictionary

prices = {
"Keyboard": 50,
"Mouse": 25,
"Monitor": 200
```

}

# Increase every price by 10 percent

updated_prices = {
product: round(price * 1.10, 2)
for product, price in prices.items()
}

print(updated_prices)
```

Output

{'Keyboard': 55.0, 'Mouse': 27.5, 'Monitor': 220.0}

Output Explanation

The first dictionary maps each number to its square. The second loops through existing key-value pairs and creates a new dictionary containing increased prices.

```

30.6 Generator Expressions

```

A generator expression looks similar to a list comprehension, but it uses parentheses instead of square brackets. It produces values one at a time instead of storing all results immediately.

Generator expressions use lazy evaluation and may save memory when working with large collections. They are often passed directly to functions such as sum(), max(), min(), any(), and all().

Example

numbers = [1, 2, 3, 4, 5]
```

# Create a generator expression

squares = (
number ** 2
for number in numbers
)

print(next(squares))
print(next(squares))

for value in squares:
print(value)
```

Output

1
```

4
9
16
25
```

Example with sum()

numbers = range(1, 1001)
```

total = sum(
number ** 2
for number in numbers
)

print(total)
```

Output

333833500

Output Explanation

The first generator returns one square each time a value is requested. The second example passes generated squares directly into sum() without first creating a complete list.

```

30.7 Multiple Loops in Comprehensions

```

A comprehension can contain more than one loop. The loops are written in the same order as equivalent nested loops. The first loop is the outer loop, and the next loop runs completely for each value from the first.

Multiple loops are useful for creating pairs, combinations, coordinates, product options, and values from nested collections. However, too many loops in one comprehension can reduce readability.

Example: Create Coordinate Pairs

x_values = [1, 2]
```

y_values = ["A", "B", "C"]

pairs = [
(x, y)
for x in x_values
for y in y_values
]

print(pairs)
```

Output

[(1, 'A'), (1, 'B'), (1, 'C'), (2, 'A'), (2, 'B'), (2, 'C')]

Equivalent Traditional Loops

x_values = [1, 2]
```

y_values = ["A", "B", "C"]

pairs = []

for x in x_values:
for y in y_values:
pairs.append((x, y))

print(pairs)
```

Output Explanation

For each number in x_values, Python loops through every letter in y_values. This produces six possible pairs.

```

30.8 Flattening Collections

```

Flattening means converting a collection containing smaller collections into one simpler collection. For example, a list of lists can be changed into one list containing all individual values.

A comprehension with two loops can flatten one level of nesting. The first loop selects each inner collection, and the second loop selects each value inside that collection.

Example

nested_numbers = [
[1, 2, 3],
[4, 5],
[6, 7, 8, 9]
```

]

flat_numbers = [
number
for inner_list in nested_numbers
for number in inner_list
]

print(flat_numbers)
```

Output

[1, 2, 3, 4, 5, 6, 7, 8, 9]

Example: Flatten and Filter

nested_numbers = [
[1, 2, 3],
[4, 5],
[6, 7, 8, 9]
```

]

even_numbers = [
number
for inner_list in nested_numbers
for number in inner_list
if number % 2 == 0
]

print(even_numbers)
```

Output

[2, 4, 6, 8]

Output Explanation

The first loop moves through each inner list. The second loop processes each value. In the second example, only values evenly divisible by two are included.

```

30.9 Filtering Data

```

Filtering means selecting only records that satisfy one or more conditions. Comprehensions can filter numbers, strings, dictionaries, objects, and other collection values.

Conditions may check numeric ranges, text content, status values, missing data, or combinations of several rules. Complex filters should sometimes be moved into a separate function to keep the comprehension readable.

Example: Filter Student Records

students = [
{"name": "Ali", "score": 85, "active": True},
{"name": "Sara", "score": 92, "active": True},
{"name": "Michael", "score": 68, "active": True},
{"name": "Emma", "score": 88, "active": False}
```

]

# Keep active students with a score of at least 80

successful_students = [
student
for student in students
if student["active"] and student["score"] >= 80
]

for student in successful_students:
print(student["name"], "-", student["score"])
```

Output

Ali - 85
```

Sara - 92
```

Example: Extract Only Names

students = [
{"name": "Ali", "score": 85},
{"name": "Sara", "score": 92},
{"name": "Michael", "score": 68}
```

]

high_score_names = [
student["name"]
for student in students
if student["score"] >= 80
]

print(high_score_names)
```

Output

['Ali', 'Sara']

Output Explanation

The first example returns complete student dictionaries. The second returns only the names of students whose scores meet the requirement.

```

30.10 Transforming Data

```

Transforming data means changing each item into a new form. A transformation may convert letter case, calculate tax, format dates, create labels, extract selected fields, or build a new record structure.

Comprehensions are especially helpful when the same transformation should be applied to every item. The original data is usually preserved while a new transformed collection is created.

Example: Clean Names

names = [
"  sara  ",
"MICHAEL",
"ali farjani",
"  emma smith "
```

]

clean_names = [
name.strip().title()
for name in names
]

print(clean_names)
```

Output

['Sara', 'Michael', 'Ali Farjani', 'Emma Smith']

Example: Transform Product Records

products = [
{"name": "Keyboard", "price": 50},
{"name": "Mouse", "price": 25},
{"name": "Monitor", "price": 200}
```

]

tax_rate = 0.13

products_with_tax = [
{
"name": product["name"],
"subtotal": product["price"],
"tax": round(product["price"] * tax_rate, 2),
"total": round(
product["price"] * (1 + tax_rate),
2
)
}
for product in products
]

for product in products_with_tax:
print(product)
```

Output

{'name': 'Keyboard', 'subtotal': 50, 'tax': 6.5, 'total': 56.5}
```

{'name': 'Mouse', 'subtotal': 25, 'tax': 3.25, 'total': 28.25}
{'name': 'Monitor', 'subtotal': 200, 'tax': 26.0, 'total': 226.0}
```

Output Explanation

The first comprehension cleans text values. The second creates a completely new dictionary for every product and adds calculated tax and total fields.

```

30.11 Comprehensions vs Traditional Loops

```

Comprehensions and traditional loops can often solve the same problem. Comprehensions are usually shorter and clearly express that a new collection is being created. Traditional loops provide more space for complex logic, debugging messages, error handling, and multiple operations.

A comprehension is a good choice when the transformation or condition is simple. A traditional loop is usually better when each iteration contains several steps or when the logic requires detailed explanation.

Comprehension Version

numbers = [1, 2, 3, 4, 5, 6]
```

even_squares = [
number ** 2
for number in numbers
if number % 2 == 0
]

print(even_squares)
```

Output

[4, 16, 36]

Traditional Loop Version

numbers = [1, 2, 3, 4, 5, 6]
```

even_squares = []

for number in numbers:
# Check whether the number is even
if number % 2 == 0:
# Calculate its square
square = number ** 2

```
    # Add the square to the result
    even_squares.append(square)
```

print(even_squares)
```

Output

[4, 16, 36]

Output Explanation

Both versions filter even numbers and square them. The comprehension is shorter. The loop version makes each step more visible and is easier to extend with additional logic.

```

30.12 Readability Considerations

```

Shorter code is not always better code. A comprehension should make the program easier to understand. When it contains several loops, several conditions, nested conditional expressions, or complex calculations, a normal loop may be clearer.

Long comprehensions can be formatted across several lines. Descriptive variable names and helper functions can also improve readability. Avoid placing unrelated side effects, such as printing or file writing, inside comprehensions.

Difficult-to-Read Example

numbers = range(1, 21)
```

result = [
number ** 2 if number % 2 == 0 else number ** 3
for number in numbers
if number % 3 != 0 and number > 2
]

print(result)
```

This code works, but a beginner may have difficulty understanding its filtering and transformation rules at the same time.

Clearer Version with a Helper Function

def transform_number(number):
if number % 2 == 0:
    return number ** 2

return number ** 3
```

numbers = range(1, 21)

result = [
transform_number(number)
for number in numbers
if number > 2 and number % 3 != 0
]

print(result)
```

Output

[16, 125, 343, 64, 1000, 2197, 196, 4096, 5832, 400]

Output Explanation

The helper function separates the transformation logic from the filtering logic. The comprehension now clearly states which values are accepted, while the function explains how each accepted value is transformed.

```

30.13 Performance Considerations

```

List comprehensions are often slightly faster than traditional loops for simple collection creation because Python performs the repeated append operation efficiently. However, performance differences should not be the only reason for selecting one style.

Memory usage is also important. A list comprehension creates and stores every result. A generator expression produces one result at a time and may be better for very large collections or values that will be consumed only once.

Example: Compare Memory Usage

import sys
```

# Store one million squared values

square_list = [
number ** 2
for number in range(1000000)
]

# Describe the same sequence lazily

square_generator = (
number ** 2
for number in range(1000000)
)

print("List size:", sys.getsizeof(square_list))
print("Generator size:", sys.getsizeof(square_generator))
```

Example Output

List size: 8448728
```

Generator size: 200
```

Output Explanation

Exact memory values vary between Python versions and computers. The list uses much more memory because it stores one million results. The generator stores only the state needed to produce future values.

Example: Time a Simple Operation

import time
```

start_time = time.perf_counter()

squares = [
number ** 2
for number in range(1000000)
]

end_time = time.perf_counter()

print("Items created:", len(squares))
print("Time:", end_time - start_time)
```

Example Output

Items created: 1000000
```

Time: 0.0815243000002
```

The exact execution time depends on the computer. Performance should be measured with realistic data rather than guessed.

```

30.14 Practical Data Processing

```

Comprehensions can combine filtering, transformation, extraction, and collection creation. They are often useful when preparing reports, cleaning imported data, calculating summaries, normalizing user input, or reorganizing records.

The following example processes sales records. It selects completed orders, calculates tax, creates a simplified report structure, and calculates a summary total.

Example: Process Sales Records

sales = [
{
    "order_id": 101,
    "customer": "Sara",
    "amount": 150.00,
    "status": "completed"
},
{
    "order_id": 102,
    "customer": "Michael",
    "amount": 85.00,
    "status": "cancelled"
},
{
    "order_id": 103,
    "customer": "Ali",
    "amount": 275.00,
    "status": "completed"
},
{
    "order_id": 104,
    "customer": "Emma",
    "amount": 400.00,
    "status": "completed"
}
```

]

tax_rate = 0.13

completed_orders = [
{
"order_id": sale["order_id"],
"customer": sale["customer"],
"subtotal": sale["amount"],
"tax": round(sale["amount"] * tax_rate, 2),
"total": round(
sale["amount"] * (1 + tax_rate),
2
)
}
for sale in sales
if sale["status"] == "completed"
]

report_total = sum(
order["total"]
for order in completed_orders
)

for order in completed_orders:
print(order)

print("Report total:", report_total)
```

Output

{'order_id': 101, 'customer': 'Sara', 'subtotal': 150.0, 'tax': 19.5, 'total': 169.5}
```

{'order_id': 103, 'customer': 'Ali', 'subtotal': 275.0, 'tax': 35.75, 'total': 310.75}
{'order_id': 104, 'customer': 'Emma', 'subtotal': 400.0, 'tax': 52.0, 'total': 452.0}
Report total: 932.25
```

Output Explanation

The list comprehension removes the cancelled order and transforms each completed order into a report dictionary. The generator expression inside sum() calculates the combined value of all completed orders.

```

30.15 Chapter Practice Exercises

```

These exercises help you practise list, set, dictionary, and generator comprehensions. Begin with simple transformations and filters before attempting nested or multi-loop comprehensions.

  1. Create a list containing the numbers from 1 to 20.
  2. Create a list containing the squares of numbers from 1 to 10.
  3. Create a list containing only even numbers from 1 to 50.
  4. Create a list containing only odd numbers from 1 to 50.
  5. Create a list of numbers divisible by both 3 and 5.
  6. Convert a list of names to uppercase.
  7. Remove spaces from the beginning and end of each word.
  8. Create labels showing whether each number is positive or negative.
  9. Create labels showing whether each score is passing or failing.
  10. Create a nested comprehension representing a 3 by 3 grid.
  11. Create a multiplication table using nested comprehensions.
  12. Create a set containing unique lowercase words.
  13. Create a set containing unique word lengths.
  14. Create a dictionary mapping numbers to their cubes.
  15. Create a dictionary mapping names to their lengths.
  16. Filter a dictionary to keep values greater than 100.
  17. Reverse the keys and values of a dictionary.
  18. Create a generator expression for square numbers.
  19. Use a generator expression with sum().
  20. Create all combinations of two lists using multiple loops.
  21. Flatten a list containing several smaller lists.
  22. Flatten a nested list and keep only even numbers.
  23. Filter student dictionaries by minimum score.
  24. Filter products by price range.
  25. Transform product prices by adding tax.
  26. Create simplified dictionaries containing selected fields.
  27. Compare a comprehension with an equivalent loop.
  28. Move a complex transformation into a helper function.
  29. Compare the memory size of a list and generator.
  30. Process completed orders and calculate a report total.

Practice Example: Word Length Dictionary

words = [
"Python",
"HTML",
"Programming",
"Data"
```

]

word_lengths = {
word: len(word)
for word in words
}

print(word_lengths)
```

Output

{'Python': 6, 'HTML': 4, 'Programming': 11, 'Data': 4}

Output Explanation

Each word becomes a dictionary key. The len() function calculates the number of characters and stores it as the corresponding value.

```

30.16 Chapter Mini Project

```

Project: Student Performance Data Processor

In this mini project, you will process a collection of student records using list, set, dictionary, and generator comprehensions. The program cleans names, calculates averages, assigns grades, filters passing students, identifies subjects, and creates a class report.

This project combines nested collections, helper functions, filtering, transformation, flattening, unique-value extraction, dictionary creation, generator expressions, and report summaries.

Complete Program

def calculate_average(scores):
"""Return the average score from a subject dictionary."""

return sum(scores.values()) / len(scores)
```

def assign_grade(average):
"""Convert a numeric average into a letter grade."""

```
if average >= 90:
    return "A"

if average >= 80:
    return "B"

if average >= 70:
    return "C"

if average >= 60:
    return "D"

return "F"
```

students = [
{
"id": 101,
"name": "  sara farjani ",
"active": True,
"scores": {
"Math": 92,
"English": 88,
"Science": 95
}
},
{
"id": 102,
"name": "MICHAEL",
"active": True,
"scores": {
"Math": 78,
"English": 84,
"Science": 81
}
},
{
"id": 103,
"name": " ali ",
"active": False,
"scores": {
"Math": 90,
"English": 91,
"Science": 89
}
},
{
"id": 104,
"name": "emma smith",
"active": True,
"scores": {
"Math": 55,
"English": 64,
"Science": 58
}
},
{
"id": 105,
"name": "DAVID",
"active": True,
"scores": {
"Math": 87,
"English": 73,
"Science": 80
}
}
]

# Clean the student names without changing the original list

clean_names = [
student["name"].strip().title()
for student in students
]

print("CLEANED NAMES")
print("-" * 50)

for name in clean_names:
print(name)

# Create a set containing every available subject

subjects = {
subject
for student in students
for subject in student["scores"]
}

print()
print("SUBJECTS")
print("-" * 50)

for subject in sorted(subjects):
print(subject)

# Create a processed record for every student

processed_students = [
{
"id": student["id"],
"name": student["name"].strip().title(),
"active": student["active"],
"scores": student["scores"],
"average": round(
calculate_average(student["scores"]),
2
),
"grade": assign_grade(
calculate_average(student["scores"])
)
}
for student in students
]

print()
print("ALL PROCESSED STUDENTS")
print("-" * 50)

for student in processed_students:
print(
student["id"],
"|",
student["name"],
"| Average:",
student["average"],
"| Grade:",
student["grade"],
"| Active:",
student["active"]
)

# Keep only active students with a passing average

passing_students = [
student
for student in processed_students
if student["active"] and student["average"] >= 60
]

print()
print("ACTIVE PASSING STUDENTS")
print("-" * 50)

for student in passing_students:
print(
student["name"],
"-",
student["average"],
"- Grade",
student["grade"]
)

# Create a dictionary for quick lookup by student ID

student_lookup = {
student["id"]: {
"name": student["name"],
"average": student["average"],
"grade": student["grade"]
}
for student in processed_students
}

print()
print("STUDENT LOOKUP")
print("-" * 50)

for student_id, information in student_lookup.items():
print(student_id, ":", information)

# Create a dictionary containing the class average for each subject

subject_averages = {
subject: round(
sum(
student["scores"][subject]
for student in students
) / len(students),
2
)
for subject in subjects
}

print()
print("SUBJECT AVERAGES")
print("-" * 50)

for subject in sorted(subject_averages):
print(subject, ":", subject_averages[subject])

# Flatten all student scores into one list

all_scores = [
score
for student in students
for score in student["scores"].values()
]

print()
print("ALL SCORES")
print("-" * 50)
print(all_scores)

# Calculate the complete class average using a generator expression

class_average = round(
sum(
score
for student in students
for score in student["scores"].values()
) / len(all_scores),
2
)

# Find the highest and lowest score

highest_score = max(all_scores)
lowest_score = min(all_scores)

# Count active students using a generator expression

active_count = sum(
1
for student in students
if student["active"]
)

# Count passing students

passing_count = len(passing_students)

# Create a grade distribution dictionary

possible_grades = {"A", "B", "C", "D", "F"}

grade_distribution = {
grade: sum(
1
for student in processed_students
if student["grade"] == grade
)
for grade in possible_grades
}

print()
print("GRADE DISTRIBUTION")
print("-" * 50)

for grade in ["A", "B", "C", "D", "F"]:
print(grade, ":", grade_distribution[grade])

print()
print("CLASS SUMMARY")
print("-" * 50)
print("Total students:", len(students))
print("Active students:", active_count)
print("Active passing students:", passing_count)
print("Class average:", class_average)
print("Highest score:", highest_score)
print("Lowest score:", lowest_score)

# Find students who need support

support_students = [
student["name"]
for student in processed_students
if student["average"] < 70
]

print()
print("STUDENTS WHO MAY NEED SUPPORT")
print("-" * 50)

if support_students:
for name in support_students:
print(name)
else:
print("No students currently need support.")
```

Output

CLEANED NAMES
```

---

Sara Farjani
Michael
Ali
Emma Smith
David

## SUBJECTS

English
Math
Science

## ALL PROCESSED STUDENTS

101 | Sara Farjani | Average: 91.67 | Grade: A | Active: True
102 | Michael | Average: 81.0 | Grade: B | Active: True
103 | Ali | Average: 90.0 | Grade: A | Active: False
104 | Emma Smith | Average: 59.0 | Grade: F | Active: True
105 | David | Average: 80.0 | Grade: B | Active: True

## ACTIVE PASSING STUDENTS

Sara Farjani - 91.67 - Grade A
Michael - 81.0 - Grade B
David - 80.0 - Grade B

## STUDENT LOOKUP

101 : {'name': 'Sara Farjani', 'average': 91.67, 'grade': 'A'}
102 : {'name': 'Michael', 'average': 81.0, 'grade': 'B'}
103 : {'name': 'Ali', 'average': 90.0, 'grade': 'A'}
104 : {'name': 'Emma Smith', 'average': 59.0, 'grade': 'F'}
105 : {'name': 'David', 'average': 80.0, 'grade': 'B'}

## SUBJECT AVERAGES

English : 80.0
Math : 80.4
Science : 80.6

## ALL SCORES

[92, 88, 95, 78, 84, 81, 90, 91, 89, 55, 64, 58, 87, 73, 80]

## GRADE DISTRIBUTION

A : 2
B : 2
C : 0
D : 0
F : 1

## CLASS SUMMARY

Total students: 5
Active students: 4
Active passing students: 3
Class average: 80.33
Highest score: 95
Lowest score: 55

## STUDENTS WHO MAY NEED SUPPORT

Emma Smith
```

Project Explanation

The calculate_average() function receives a dictionary of subject scores. It adds the values and divides by the number of subjects. The assign_grade() function converts each average into a letter grade.

The first list comprehension cleans all student names with strip() and title(). The set comprehension gathers every subject and automatically removes duplicates.

The processed_students comprehension creates a new dictionary for every student. It preserves the identification and score information while adding a cleaned name, calculated average, and grade.

The passing_students comprehension filters the processed collection. It keeps only active students whose averages are at least 60.

The dictionary comprehension named student_lookup uses each student ID as a key. This makes it easier to find report information for a specific student.

The subject_averages comprehension creates one dictionary entry for every subject. A generator expression calculates the total score for that subject across all students.

The all_scores comprehension flattens the nested score dictionaries into one list. This list is used to find the highest score, lowest score, and total number of scores.

Generator expressions calculate the class average and number of active students. They produce values only as the summary functions request them.

The final dictionary comprehension counts how many students received each possible grade. Another list comprehension identifies students whose averages are below 70.

How to Run the Mini Project

  1. Open Visual Studio Code, IDLE, PyCharm, or another Python editor.
  2. Create a new file named student_data_processor.py.
  3. Copy the complete program into the file.
  4. Save the file.
  5. Open a terminal in the same folder.
  6. Run python student_data_processor.py.
  7. On some computers, run python3 student_data_processor.py.
  8. Review the cleaned names and processed student records.
  9. Review the subject averages and grade distribution.
  10. Add more students and scores to the original collection.
  11. Run the program again and compare the results.

Project Challenges

  • Ask the user to enter new student records.
  • Load student records from a JSON file.
  • Save the final report to a text file.
  • Sort students from highest to lowest average.
  • Display the highest student in each subject.
  • Calculate averages for active students only.
  • Create a list of students receiving each grade.
  • Add attendance information.
  • Filter students by both attendance and average.
  • Add more subjects dynamically.
  • Create a report containing only selected fields.
  • Find students who improved between two terms.
  • Create a dictionary grouped by grade.
  • Compare list-comprehension and generator memory usage.
  • Create a menu for viewing different reports.
```
Chapter 2: Development EnvironmentPrepare Your JavaScript Workspace

A modern course built to help learners study step by step with clarity, comfort, and confidence.