Python Collections - Practice Questions and Solutions

List, Tuple, Dictionary, Set – Complete Practice Set


This practice set covers strings and all four major Python collections. Questions are grouped by collection type, then by difficulty within each section. The final section has mixed questions that combine multiple collections, loops, and conditionals. Try each question before reading the solution.


Table of Contents


Part 1 – Lists

A list is an ordered, mutable collection. It allows duplicate values and supports indexing, slicing, appending, and sorting.


L1 – Basic Indexing and Slicing

Given the list below, write code to:

  • Print the first element
  • Print the last element
  • Print elements from index 2 to 5 (inclusive)
  • Print every alternate element
cities = ["Delhi", "Mumbai", "Bangalore", "Chennai", "Hyderabad", "Pune", "Kolkata", "Ahmedabad"]

Expected Output:

First : Delhi
Last  : Ahmedabad
Slice : ['Bangalore', 'Chennai', 'Hyderabad', 'Pune']
Every alternate : ['Delhi', 'Bangalore', 'Hyderabad', 'Kolkata']

Solution:

cities = ["Delhi", "Mumbai", "Bangalore", "Chennai", "Hyderabad", "Pune", "Kolkata", "Ahmedabad"]

print("First :", cities[0])
print("Last  :", cities[-1])
print("Slice :", cities[2:6])
print("Every alternate :", cities[::2])

L2 – List Methods

Start with the list below and apply the following operations in order. Print the list after each step.

  • Append “Jaipur”
  • Insert “Surat” at index 2
  • Remove “Chennai”
  • Sort the list alphabetically
  • Reverse it
cities = ["Delhi", "Mumbai", "Bangalore", "Chennai", "Hyderabad"]

Solution:

cities = ["Delhi", "Mumbai", "Bangalore", "Chennai", "Hyderabad"]

cities.append("Jaipur")
print("After append :", cities)

cities.insert(2, "Surat")
print("After insert :", cities)

cities.remove("Chennai")
print("After remove :", cities)

cities.sort()
print("After sort   :", cities)

cities.reverse()
print("After reverse:", cities)

L3 – List Comprehension with Transformation

Given the list of product prices below, use a list comprehension to:

  • Create a new list with 18% GST added to each price
  • Create another list with only prices above Rs.500 (after GST)
prices = [120, 450, 800, 250, 1200, 60, 3500, 175]

Solution:

prices = [120, 450, 800, 250, 1200, 60, 3500, 175]

with_gst = [round(p * 1.18, 2) for p in prices]
print("With GST:", with_gst)

expensive = [p for p in with_gst if p > 500]
print("Above 500:", expensive)

L4 – Nested List (2D)

You have a marks matrix for 4 students across 3 subjects. Write code to:

  • Print the marks of the second student (index 1)
  • Print the third subject marks for all students
  • Find the student with the highest total
marks = [
    [78, 85, 90],   # Aarav
    [92, 76, 88],   # Priya
    [65, 70, 80],   # Rohan
    [88, 91, 95],   # Sneha
]
names = ["Aarav", "Priya", "Rohan", "Sneha"]

Solution:

marks = [
    [78, 85, 90],
    [92, 76, 88],
    [65, 70, 80],
    [88, 91, 95],
]
names = ["Aarav", "Priya", "Rohan", "Sneha"]

print("Second student's marks:", marks[1])

print("Third subject marks:", [row[2] for row in marks])

totals = [sum(row) for row in marks]
max_total = max(totals)
topper    = names[totals.index(max_total)]
print(f"Topper: {topper} with {max_total} marks")

L5 – List Operations Without Built-ins

Write a function second_largest(lst) that returns the second largest unique number from a list. Do not use sorted() or max().

numbers = [45, 92, 78, 92, 55, 88, 78, 100, 63]

Expected Output:

Second largest: 92

Solution:

def second_largest(lst):
    unique = []
    for n in lst:
        if n not in unique:
            unique.append(n)

    # Find max manually
    first = unique[0]
    for n in unique:
        if n > first:
            first = n

    # Find second max (largest value that is not the max)
    second = None
    for n in unique:
        if n == first:
            continue
        if second is None or n > second:
            second = n

    return second

numbers = [45, 92, 78, 92, 55, 88, 78, 100, 63]
print("Second largest:", second_largest(numbers))

L6 – Rotate a List

Write a function rotate_left(lst, k) that rotates a list to the left by k positions without using any slicing tricks – use a loop.

items = [10, 20, 30, 40, 50]
rotate_left(items, 2)  # Expected: [30, 40, 50, 10, 20]

Solution:

def rotate_left(lst, k):
    k = k % len(lst)   # handle k larger than list length
    result = []
    for i in range(k, len(lst)):
        result.append(lst[i])
    for i in range(k):
        result.append(lst[i])
    return result

items = [10, 20, 30, 40, 50]
print(rotate_left(items, 2))   # [30, 40, 50, 10, 20]
print(rotate_left(items, 7))   # same as rotating by 2

L7 – Chunk a List

Write a function chunk(lst, size) that splits a list into smaller lists of a given size. The last chunk may be smaller.

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
chunk(data, 3)
# Expected: [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

Solution:

def chunk(lst, size):
    result = []
    for i in range(0, len(lst), size):
        result.append(lst[i:i+size])
    return result

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(chunk(data, 3))
print(chunk(data, 4))

Part 2 – Strings

A string is an ordered, immutable sequence of characters. Like a tuple, you can index and slice it, but you cannot change individual characters in place. Python has a rich set of built-in string methods for searching, formatting, and transforming text.


ST1 – Basic Indexing and Slicing

Given the string below, write code to:

  • Print the first character
  • Print the last character
  • Print characters from index 8 to 13
  • Print the string in reverse
  • Print the length of the string
message = "Welcome to Python"

Expected Output:

First    : W
Last     : n
Slice    : to Py
Reversed : nohtyP ot emocleW
Length   : 17

Solution:

message = "Welcome to Python"

print("First    :", message[0])
print("Last     :", message[-1])
print("Slice    :", message[8:13])
print("Reversed :", message[::-1])
print("Length   :", len(message))

ST2 – String Methods

Start with the string below and apply the following operations. Print the result after each step.

  • Convert to uppercase
  • Convert to lowercase
  • Strip the extra whitespace from both ends
  • Replace “Python” with “Coding”
  • Split the sentence into a list of words
text = "   Learning Python is Fun   "

Solution:

text = "   Learning Python is Fun   "

print(text.upper())
print(text.lower())
print(text.strip())
print(text.strip().replace("Python", "Coding"))
print(text.strip().split())

ST3 – String Checking Methods

Given the strings below, use appropriate string methods to answer each question.

word1    = "Python3"
word2    = "codeverra"
word3    = "  "
sentence = "Learning Python is fun"
  • Is word1 made of only alphabets?
  • Is word1 alphanumeric?
  • Does word2 start with "code"?
  • Does sentence end with "fun"?
  • Is "Python" present in sentence?
  • Is word3 blank (only whitespace)?

Solution:

word1    = "Python3"
word2    = "codeverra"
word3    = "  "
sentence = "Learning Python is fun"

print(word1.isalpha())            # False -- contains a digit
print(word1.isalnum())            # True
print(word2.startswith("code"))   # True
print(sentence.endswith("fun"))   # True
print("Python" in sentence)       # True
print(word3.strip() == "")        # True

ST4 – Palindrome Checker

Write a function is_palindrome(text) that returns True if the text reads the same forwards and backwards. Ignore spaces and case.

is_palindrome("racecar")                        # True
is_palindrome("A man a plan a canal Panama")    # True
is_palindrome("hello")                          # False
is_palindrome("Madam")                          # True

Solution:

def is_palindrome(text):
    cleaned = text.replace(" ", "").lower()
    return cleaned == cleaned[::-1]

print(is_palindrome("racecar"))                      # True
print(is_palindrome("A man a plan a canal Panama"))  # True
print(is_palindrome("hello"))                        # False
print(is_palindrome("Madam"))                        # True

ST5 – Count Vowels and Consonants

Write a function count_letters(text) that counts vowels and consonants in a string. Ignore spaces, digits, and punctuation.

text = "Learning Python at Codeverra is Amazing"

Expected Output:

Vowels     : 13
Consonants : 21

Solution:

def count_letters(text):
    vowels  = "aeiouAEIOU"
    v_count = 0
    c_count = 0
    for char in text:
        if char.isalpha():
            if char in vowels:
                v_count += 1
            else:
                c_count += 1
    return v_count, c_count

text = "Learning Python at Codeverra is Amazing"
vowels, consonants = count_letters(text)
print(f"Vowels     : {vowels}")
print(f"Consonants : {consonants}")

Part 3 – Tuples

A tuple is an ordered, immutable collection. Once created, its values cannot be changed. Tuples are used for fixed data, function return values, and dictionary keys.


T1 – Tuple Basics and Unpacking

employee = ("Vikram Nair", "Engineering", 85000, "Bangalore")
  • Unpack this tuple into four variables
  • Print each variable on a separate line
  • Try to change the salary (third element) – explain what happens

Solution:

employee = ("Vikram Nair", "Engineering", 85000, "Bangalore")

name, department, salary, city = employee

print("Name       :", name)
print("Department :", department)
print("Salary     :", salary)
print("City       :", city)

# Attempting to modify raises a TypeError
# employee[2] = 90000   -->  TypeError: 'tuple' object does not support item assignment

# The right way to "update" a tuple is to create a new one
updated_employee = employee[:2] + (90000,) + employee[3:]
print("Updated:", updated_employee)

T2 – Tuple of Tuples (Loop and Unpack)

You have a list of tuples representing train journeys. Print a formatted summary for each journey.

journeys = [
    ("Rajdhani Express", "Delhi",     "Mumbai",    16),
    ("Shatabdi",         "Chennai",   "Bangalore",  5),
    ("Duronto",          "Kolkata",   "Delhi",      17),
    ("Vande Bharat",     "Hyderabad", "Pune",        8),
]

Expected Output:

Rajdhani Express : Delhi -> Mumbai (16 hrs)
Shatabdi         : Chennai -> Bangalore (5 hrs)
Duronto          : Kolkata -> Delhi (17 hrs)
Vande Bharat     : Hyderabad -> Pune (8 hrs)

Solution:

journeys = [
    ("Rajdhani Express", "Delhi",     "Mumbai",    16),
    ("Shatabdi",         "Chennai",   "Bangalore",  5),
    ("Duronto",          "Kolkata",   "Delhi",      17),
    ("Vande Bharat",     "Hyderabad", "Pune",        8),
]

for train, origin, destination, hours in journeys:
    print(f"{train:<18}: {origin} -> {destination} ({hours} hrs)")

T3 – Tuple as Dictionary Key

Tuples can be dictionary keys because they are immutable. Create a dictionary that maps (city, year) tuples to population (in lakhs).

Then write a loop to print cities whose population grew between 2020 and 2023.

population = {
    ("Delhi",     2020): 300,
    ("Delhi",     2023): 320,
    ("Mumbai",    2020): 205,
    ("Mumbai",    2023): 210,
    ("Bangalore", 2020): 120,
    ("Bangalore", 2023): 140,
    ("Chennai",   2020): 92,
    ("Chennai",   2023): 90,
}

Solution:

population = {
    ("Delhi",     2020): 300,
    ("Delhi",     2023): 320,
    ("Mumbai",    2020): 205,
    ("Mumbai",    2023): 210,
    ("Bangalore", 2020): 120,
    ("Bangalore", 2023): 140,
    ("Chennai",   2020): 92,
    ("Chennai",   2023): 90,
}

cities = {city for city, year in population.keys()}

for city in sorted(cities):
    pop_2020 = population[(city, 2020)]
    pop_2023 = population[(city, 2023)]
    if pop_2023 > pop_2020:
        growth = pop_2023 - pop_2020
        print(f"{city}: grew by {growth} lakhs")

T4 – Named Tuple (collections.namedtuple)

Use namedtuple to create a Student type. Create 3 student instances and print a report.

Solution:

from collections import namedtuple

Student = namedtuple("Student", ["name", "roll_no", "marks", "city"])

s1 = Student("Aarav",  101, 88, "Delhi")
s2 = Student("Priya",  102, 92, "Mumbai")
s3 = Student("Rohan",  103, 75, "Bangalore")

students = [s1, s2, s3]

for s in students:
    grade = "A" if s.marks >= 85 else "B" if s.marks >= 70 else "C"
    print(f"Roll {s.roll_no} | {s.name:<8} | {s.marks} | {grade} | {s.city}")

Why namedtuple? You get tuple immutability but can access fields by name (s.marks) instead of index (s[2]). Much more readable.


T5 – Swap Without a Temp Variable

Python allows elegant swapping using tuple unpacking. Demonstrate this and write a function that takes a list of tuples and swaps each pair.

pairs = [(1, 2), (10, 20), ("Delhi", "Mumbai"), (True, False)]

Expected Output:

(2, 1)
(20, 10)
('Mumbai', 'Delhi')
(False, True)

Solution:

# Classic swap using tuple unpacking
a = 10
b = 20
a, b = b, a
print(a, b)   # 20 10

# Swap all pairs in a list
pairs = [(1, 2), (10, 20), ("Delhi", "Mumbai"), (True, False)]

swapped = [(b, a) for a, b in pairs]
print(swapped)

Part 4 – Dictionaries

A dictionary is an ordered (Python 3.7+), mutable collection of key-value pairs. Keys must be unique and immutable. Dictionaries are optimised for fast lookup by key.


D1 – Dictionary Basics

Given the dictionary below:

  • Access Kohli’s runs
  • Add a new player “Hardik” with 320 runs
  • Update Rohit’s runs to 580
  • Delete Dhoni’s entry
  • Check if “Bumrah” is in the dictionary
ipl_runs = {
    "Rohit":  520,
    "Kohli":  639,
    "Dhoni":  210,
    "Jadeja": 180,
}

Solution:

ipl_runs = {
    "Rohit":  520,
    "Kohli":  639,
    "Dhoni":  210,
    "Jadeja": 180,
}

print(ipl_runs["Kohli"])         # 639

ipl_runs["Hardik"] = 320
print(ipl_runs)

ipl_runs["Rohit"] = 580
print(ipl_runs["Rohit"])

del ipl_runs["Dhoni"]
print(ipl_runs)

print("Bumrah" in ipl_runs)      # False
print("Kohli"  in ipl_runs)      # True

D2 – Safe Access with get() and setdefault()

The .get() method avoids KeyError when accessing a key that might not exist.

Given the inventory below, write code that:

  • Prints the stock for “Laptop” and “Printer” using .get() with a default of 0
  • Uses setdefault() to add “Printer” with a stock of 5 if it does not exist
inventory = {
    "Laptop":  15,
    "Phone":   42,
    "Tablet":  8,
    "Monitor": 20,
}

Solution:

inventory = {
    "Laptop":  15,
    "Phone":   42,
    "Tablet":  8,
    "Monitor": 20,
}

print(inventory.get("Laptop",  0))    # 15
print(inventory.get("Printer", 0))    # 0  -- no error

inventory.setdefault("Printer", 5)    # adds only if key is missing
print(inventory["Printer"])           # 5

inventory.setdefault("Laptop", 100)   # does NOT overwrite existing key
print(inventory["Laptop"])            # still 15

D3 – Merging Dictionaries

You have sales data from two regions. Merge them into one dictionary. For cities that appear in both, sum the values.

north = {"Delhi": 450, "Chandigarh": 120, "Lucknow": 200}
south = {"Chennai": 380, "Bangalore": 520, "Delhi": 150}

Expected Output:

{'Delhi': 600, 'Chandigarh': 120, 'Lucknow': 200, 'Chennai': 380, 'Bangalore': 520}

Solution:

north = {"Delhi": 450, "Chandigarh": 120, "Lucknow": 200}
south = {"Chennai": 380, "Bangalore": 520, "Delhi": 150}

merged = dict(north)   # start with a copy of north

for city, sales in south.items():
    if city in merged:
        merged[city] += sales     # sum if city already exists
    else:
        merged[city] = sales      # add new city

print(merged)

D4 – Inverting a Dictionary

Write a function that inverts a dictionary – keys become values and values become keys. Handle cases where multiple keys share the same value by grouping them into a list.

departments = {
    "Aarav":  "Engineering",
    "Priya":  "HR",
    "Rohan":  "Engineering",
    "Sneha":  "Marketing",
    "Karan":  "HR",
    "Meera":  "Engineering",
}

Expected Output:

{'Engineering': ['Aarav', 'Rohan', 'Meera'], 'HR': ['Priya', 'Karan'], 'Marketing': ['Sneha']}

Solution:

departments = {
    "Aarav":  "Engineering",
    "Priya":  "HR",
    "Rohan":  "Engineering",
    "Sneha":  "Marketing",
    "Karan":  "HR",
    "Meera":  "Engineering",
}

inverted = {}
for name, dept in departments.items():
    if dept not in inverted:
        inverted[dept] = []
    inverted[dept].append(name)

print(inverted)

D5 – Nested Dictionary

You have a nested dictionary representing student report cards. Write code to:

  • Print Priya’s science marks
  • Find the overall class topper (highest average across all subjects)
  • Count how many students scored above 80 in maths
report_cards = {
    "Aarav": {"maths": 88, "science": 92, "english": 85},
    "Priya": {"maths": 75, "science": 68, "english": 79},
    "Rohan": {"maths": 55, "science": 60, "english": 72},
    "Sneha": {"maths": 95, "science": 98, "english": 91},
}

Solution:

report_cards = {
    "Aarav": {"maths": 88, "science": 92, "english": 85},
    "Priya": {"maths": 75, "science": 68, "english": 79},
    "Rohan": {"maths": 55, "science": 60, "english": 72},
    "Sneha": {"maths": 95, "science": 98, "english": 91},
}

# Priya's science marks
print("Priya's science:", report_cards["Priya"]["science"])

# Class topper by average
topper     = ""
top_avg    = 0
for name, subjects in report_cards.items():
    avg = sum(subjects.values()) / len(subjects)
    if avg > top_avg:
        top_avg = avg
        topper  = name
print(f"Topper: {topper} with avg {top_avg:.1f}")

# Count students above 80 in maths
above_80 = sum(1 for data in report_cards.values() if data["maths"] > 80)
print(f"Students above 80 in maths: {above_80}")

D6 – Word Frequency with Dictionary

Write a function that takes a sentence and returns a dictionary with each word and how many times it appears. Ignore case. Then print the top 3 most frequent words.

text = "to be or not to be that is the question to be is to live"

Expected Output:

Top 3 words:
to  : 4
be  : 3
is  : 2

Solution:

def word_frequency(text):
    freq = {}
    for word in text.lower().split():
        freq[word] = freq.get(word, 0) + 1
    return freq

text = "to be or not to be that is the question to be is to live"
freq = word_frequency(text)

sorted_freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)

print("Top 3 words:")
for word, count in sorted_freq[:3]:
    print(f"{word:<4}: {count}")

Part 5 – Sets

A set is an unordered, mutable collection of unique elements. It has no duplicates and no index. Sets shine when you need fast membership checks or mathematical set operations.


S1 – Set Basics and Deduplication

Given a list with many duplicate values, use a set to find all unique values. Then convert back to a sorted list.

orders = ["Delhi", "Mumbai", "Delhi", "Bangalore", "Pune",
          "Mumbai", "Delhi", "Chennai", "Pune", "Bangalore"]

Expected Output:

Unique cities (5): ['Bangalore', 'Chennai', 'Delhi', 'Mumbai', 'Pune']

Solution:

orders = ["Delhi", "Mumbai", "Delhi", "Bangalore", "Pune",
          "Mumbai", "Delhi", "Chennai", "Pune", "Bangalore"]

unique = sorted(set(orders))
print(f"Unique cities ({len(unique)}): {unique}")

S2 – Set Operations (Union, Intersection, Difference)

Two cricket teams have been announced. Use set operations to find:

  • All players across both teams (union)
  • Players selected in both teams (intersection)
  • Players in Team A but not Team B (difference)
  • Players in exactly one team but not both (symmetric difference)
team_a = {"Rohit", "Virat", "Shubman", "Pant", "Jadeja", "Bumrah", "Siraj"}
team_b = {"Rohit", "Shubman", "Dhoni",  "Jadeja", "Ashwin", "Bumrah", "Kuldeep"}

Solution:

team_a = {"Rohit", "Virat", "Shubman", "Pant", "Jadeja", "Bumrah", "Siraj"}
team_b = {"Rohit", "Shubman", "Dhoni",  "Jadeja", "Ashwin", "Bumrah", "Kuldeep"}

print("All players (union)       :", sorted(team_a | team_b))
print("In both teams (intersect) :", sorted(team_a & team_b))
print("Only in Team A (diff)     :", sorted(team_a - team_b))
print("Only in Team B (diff)     :", sorted(team_b - team_a))
print("Exactly one team (sym diff):", sorted(team_a ^ team_b))

S3 – Set Methods: add, remove, discard

registered = {"Aarav", "Priya", "Rohan", "Sneha"}
  • Add “Karan” to the set
  • Remove “Rohan” using remove() – show what happens if the name is not there
  • Remove “Meera” using discard() – show that no error is raised
  • Check if “Priya” is in the set

Solution:

registered = {"Aarav", "Priya", "Rohan", "Sneha"}

registered.add("Karan")
print("After add:", registered)

registered.remove("Rohan")
print("After remove:", registered)

# registered.remove("Meera")   # raises KeyError -- "Meera" is not in set

registered.discard("Meera")    # no error even if "Meera" does not exist
print("After discard:", registered)

print("Priya in set:", "Priya" in registered)

S4 – Subset and Superset

You have a set of required skills for a job and a set of skills each candidate has. Check whether each candidate qualifies.

required  = {"Python", "SQL", "Pandas"}

candidate_a = {"Python", "SQL", "Pandas", "Excel", "Tableau"}
candidate_b = {"Python", "SQL"}
candidate_c = {"Python", "SQL", "Pandas"}
candidate_d = {"Java",   "SQL", "Spring"}

Expected Output:

Candidate A: Qualified  (has all required skills + more)
Candidate B: Not qualified (missing: {'Pandas'})
Candidate C: Qualified
Candidate D: Not qualified (missing: {'Python', 'Pandas'})

Solution:

required    = {"Python", "SQL", "Pandas"}
candidates  = {
    "Candidate A": {"Python", "SQL", "Pandas", "Excel", "Tableau"},
    "Candidate B": {"Python", "SQL"},
    "Candidate C": {"Python", "SQL", "Pandas"},
    "Candidate D": {"Java",   "SQL", "Spring"},
}

for name, skills in candidates.items():
    missing = required - skills
    if not missing:
        print(f"{name}: Qualified")
    else:
        print(f"{name}: Not qualified (missing: {missing})")

S5 – Frozen Set

A frozenset is an immutable set – useful as a dictionary key or when you want a set that cannot change.

Demonstrate the difference between set and frozenset and use a frozenset as a dictionary key.

Solution:

# Regular set is mutable
tags = set(["python", "data", "beginner"])
tags.add("loops")
print("Set:", tags)

# Frozenset is immutable
frozen = frozenset(["python", "data", "beginner"])
# frozen.add("loops")   --> AttributeError: 'frozenset' object has no attribute 'add'

# frozenset can be used as a dictionary key (regular set cannot)
course_levels = {
    frozenset(["python", "beginner"]):     "Python 101",
    frozenset(["python", "intermediate"]): "Python OOP",
    frozenset(["sql",    "beginner"]):     "SQL Basics",
}

search = frozenset(["python", "beginner"])
print(course_levels[search])    # Python 101

Part 6 – Mixed Questions

These questions combine multiple collections with loops, conditionals, and comprehensions.


M1 – Frequency Counter (List + Dictionary + Loop)

Given a list of exam scores, write a program that:

  • Counts how many students fall in each grade band
  • Prints the result sorted from highest grade band to lowest
scores = [88, 45, 72, 95, 60, 55, 83, 91, 38, 74, 66, 49, 87, 100, 52]

Expected Output:

Distinction (>=85) : 4
First Class (>=60) : 5
Pass        (>=40) : 4
Fail        (<40)  : 1

Solution:

scores = [88, 45, 72, 95, 60, 55, 83, 91, 38, 74, 66, 49, 87, 100, 52]

bands = {"Distinction": 0, "First Class": 0, "Pass": 0, "Fail": 0}

for s in scores:
    if s >= 85:
        bands["Distinction"] += 1
    elif s >= 60:
        bands["First Class"] += 1
    elif s >= 40:
        bands["Pass"] += 1
    else:
        bands["Fail"] += 1

for band, count in bands.items():
    print(f"{band:<12}: {count}")

M2 – Anagram Checker (String + Set + Dictionary)

Write a function are_anagrams(s1, s2) that returns True if two strings are anagrams of each other (same letters, different order). Ignore spaces and case.

are_anagrams("listen",  "silent")      # True
are_anagrams("Triangle", "Integral")   # True
are_anagrams("hello",    "world")      # False
are_anagrams("Astronomer", "Moon starer")  # True (ignore spaces)

Solution:

def are_anagrams(s1, s2):
    # Remove spaces and convert to lowercase
    clean1 = s1.replace(" ", "").lower()
    clean2 = s2.replace(" ", "").lower()

    # Build frequency dictionaries
    freq1 = {}
    for char in clean1:
        freq1[char] = freq1.get(char, 0) + 1

    freq2 = {}
    for char in clean2:
        freq2[char] = freq2.get(char, 0) + 1

    return freq1 == freq2

print(are_anagrams("listen",      "silent"))       # True
print(are_anagrams("Triangle",    "Integral"))     # True
print(are_anagrams("hello",       "world"))        # False
print(are_anagrams("Astronomer",  "Moon starer"))  # True

M3 – Group Transactions (List of Dicts + Nested Dict + Loop)

Given a list of bank transactions, group them by category and compute:

  • Total spent per category
  • Number of transactions per category
  • Average transaction per category
transactions = [
    {"desc": "Zomato order",     "amount": 450,  "category": "Food"},
    {"desc": "Metro recharge",   "amount": 200,  "category": "Travel"},
    {"desc": "Amazon purchase",  "amount": 1800, "category": "Shopping"},
    {"desc": "Swiggy order",     "amount": 380,  "category": "Food"},
    {"desc": "Uber ride",        "amount": 320,  "category": "Travel"},
    {"desc": "Grocery store",    "amount": 950,  "category": "Food"},
    {"desc": "Flipkart order",   "amount": 2200, "category": "Shopping"},
    {"desc": "OLA ride",         "amount": 180,  "category": "Travel"},
    {"desc": "Restaurant",       "amount": 1100, "category": "Food"},
]

Expected Output:

Category   | Transactions | Total Spent | Avg per Transaction
Food       |      4       |    Rs.2880  |    Rs.720.0
Travel     |      3       |    Rs.700   |    Rs.233.33
Shopping   |      2       |    Rs.4000  |    Rs.2000.0

Solution:

transactions = [
    {"desc": "Zomato order",     "amount": 450,  "category": "Food"},
    {"desc": "Metro recharge",   "amount": 200,  "category": "Travel"},
    {"desc": "Amazon purchase",  "amount": 1800, "category": "Shopping"},
    {"desc": "Swiggy order",     "amount": 380,  "category": "Food"},
    {"desc": "Uber ride",        "amount": 320,  "category": "Travel"},
    {"desc": "Grocery store",    "amount": 950,  "category": "Food"},
    {"desc": "Flipkart order",   "amount": 2200, "category": "Shopping"},
    {"desc": "OLA ride",         "amount": 180,  "category": "Travel"},
    {"desc": "Restaurant",       "amount": 1100, "category": "Food"},
]

summary = {}

for t in transactions:
    cat = t["category"]
    if cat not in summary:
        summary[cat] = {"count": 0, "total": 0}
    summary[cat]["count"] += 1
    summary[cat]["total"] += t["amount"]

print(f"{'Category':<10} | {'Txns':>5} | {'Total':>12} | {'Avg':>10}")
print("-" * 50)

for cat, data in summary.items():
    avg = round(data["total"] / data["count"], 2)
    print(f"{cat:<10} | {data['count']:>5} | Rs.{data['total']:>9} | Rs.{avg:>9}")

M4 – Find Common Elements Across Multiple Lists (Set + Loop)

Given results from three different quiz rounds, find:

  • Students who passed all three rounds
  • Students who passed exactly two rounds
  • Students who passed only one round
round1 = ["Aarav", "Priya", "Rohan", "Sneha", "Karan", "Meera"]
round2 = ["Priya", "Sneha", "Karan", "Arjun", "Divya"]
round3 = ["Aarav", "Priya", "Sneha", "Arjun", "Vikram"]

Solution:

round1 = set(["Aarav", "Priya", "Rohan", "Sneha", "Karan", "Meera"])
round2 = set(["Priya", "Sneha", "Karan", "Arjun", "Divya"])
round3 = set(["Aarav", "Priya", "Sneha", "Arjun", "Vikram"])

all_three  = round1 & round2 & round3
exactly_two = (
    (round1 & round2) |
    (round2 & round3) |
    (round1 & round3)
) - all_three

all_students = round1 | round2 | round3
only_one     = all_students - (round1 & round2) - (round2 & round3) - (round1 & round3)

print("Passed all three :", sorted(all_three))
print("Passed exactly two:", sorted(exactly_two))
print("Passed only one  :", sorted(only_one))

M5 – Top N with Tuples and Sorting (List + Tuple + Sort)

Given a list of product sales tuples, write a function top_n(sales, n) that returns the top n products by revenue. Each tuple is (product_name, units_sold, price_per_unit).

sales = [
    ("Laptop",    120, 65000),
    ("Phone",     450, 18000),
    ("Tablet",    210, 32000),
    ("Headphones",780, 2500),
    ("Monitor",   95,  22000),
    ("Keyboard",  640, 1200),
    ("Mouse",     900, 800),
]

Expected Output for top_n(sales, 3):

Rank 1: Phone      -- Revenue: Rs.81,00,000 (450 units)
Rank 2: Laptop     -- Revenue: Rs.78,00,000 (120 units)
Rank 3: Tablet     -- Revenue: Rs.67,20,000 (210 units)

Solution:

sales = [
    ("Laptop",    120, 65000),
    ("Phone",     450, 18000),
    ("Tablet",    210, 32000),
    ("Headphones",780, 2500),
    ("Monitor",   95,  22000),
    ("Keyboard",  640, 1200),
    ("Mouse",     900, 800),
]

def top_n(sales, n):
    # Create list of (name, revenue, units) tuples
    with_revenue = []
    for name, units, price in sales:
        revenue = units * price
        with_revenue.append((name, revenue, units))

    # Sort by revenue descending
    with_revenue.sort(key=lambda x: x[1], reverse=True)

    for rank, (name, revenue, units) in enumerate(with_revenue[:n], start=1):
        print(f"Rank {rank}: {name:<12} -- Revenue: Rs.{revenue:,} ({units} units)")

top_n(sales, 3)

M6 – Matrix Transpose Using Lists (Nested List + Comprehension)

Write a function transpose(matrix) that returns the transpose of a 2D list (rows become columns and columns become rows). Do it in two ways: with a loop and with a list comprehension.

matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
]
# Expected transpose:
# [[1, 4, 7],
#  [2, 5, 8],
#  [3, 6, 9]]

Solution:

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

# Method 1: loop
def transpose_loop(matrix):
    rows = len(matrix)
    cols = len(matrix[0])
    result = [[0] * rows for _ in range(cols)]
    for i in range(rows):
        for j in range(cols):
            result[j][i] = matrix[i][j]
    return result

# Method 2: list comprehension
def transpose_comprehension(matrix):
    return [[row[i] for row in matrix] for i in range(len(matrix[0]))]

print(transpose_loop(matrix))
print(transpose_comprehension(matrix))

M7 – Inventory Manager (Dict + List + Conditional + Loop)

You manage a small shop. Write a program that:

  • Starts with an inventory dictionary
  • Processes a list of sales
  • Reduces stock after each sale
  • Prints a “LOW STOCK” warning if quantity falls below 5
  • Prints “OUT OF STOCK” and skips the sale if quantity is 0
inventory = {
    "Pen":      50,
    "Notebook": 20,
    "Eraser":   8,
    "Ruler":    3,
    "Compass":  0,
}

sales = [
    ("Pen",      12),
    ("Notebook",  5),
    ("Compass",   1),
    ("Eraser",    5),
    ("Ruler",     2),
    ("Pen",      40),
    ("Notebook", 18),
]

Solution:

inventory = {
    "Pen":      50,
    "Notebook": 20,
    "Eraser":   8,
    "Ruler":    3,
    "Compass":  0,
}

sales = [
    ("Pen",      12),
    ("Notebook",  5),
    ("Compass",   1),
    ("Eraser",    5),
    ("Ruler",     2),
    ("Pen",      40),
    ("Notebook", 18),
]

for item, qty in sales:
    if inventory.get(item, 0) == 0:
        print(f"OUT OF STOCK : {item} -- sale of {qty} skipped")
        continue

    if qty > inventory[item]:
        print(f"INSUFFICIENT : Only {inventory[item]} {item}(s) left, cannot sell {qty}")
        continue

    inventory[item] -= qty
    remaining = inventory[item]

    if remaining < 5:
        print(f"Sold {qty} {item}(s). Remaining: {remaining}  [LOW STOCK]")
    else:
        print(f"Sold {qty} {item}(s). Remaining: {remaining}")

print("\nFinal Inventory:")
for item, qty in inventory.items():
    print(f"  {item:<10}: {qty}")

M8 – Caesar Cipher (String + List + Dictionary + Loop)

Write a function caesar_encrypt(text, shift) and caesar_decrypt(text, shift) that encrypts and decrypts text using the Caesar cipher. Only shift letters, leave spaces and punctuation unchanged.

message = "Attack at Dawn"
shift   = 3

encrypted = caesar_encrypt(message, shift)
decrypted = caesar_decrypt(encrypted, shift)
# encrypted: "Dwwdfn dw Gdzq"
# decrypted: "Attack at Dawn"

Solution:

def caesar_encrypt(text, shift):
    result = []
    for char in text:
        if char.isalpha():
            base  = ord("A") if char.isupper() else ord("a")
            shifted = chr((ord(char) - base + shift) % 26 + base)
            result.append(shifted)
        else:
            result.append(char)
    return "".join(result)

def caesar_decrypt(text, shift):
    return caesar_encrypt(text, -shift)

message   = "Attack at Dawn"
shift     = 3
encrypted = caesar_encrypt(message, shift)
decrypted = caesar_decrypt(encrypted, shift)

print(f"Original : {message}")
print(f"Encrypted: {encrypted}")
print(f"Decrypted: {decrypted}")

M9 – Student Ranking System (Full Pipeline)

Given a list of student records, write a complete program that:

  1. Calculates total and percentage for each student
  2. Assigns grade: “Distinction” (>=85%), “First Class” (>=60%), “Pass” (>=40%), “Fail” (<40%)
  3. Ranks students from topper to lowest
  4. Identifies students who improved from their previous percentage (given separately)
  5. Prints a complete ranked report
students = [
    {"name": "Aarav",  "maths": 88, "science": 92, "english": 85, "history": 78, "cs": 95},
    {"name": "Priya",  "maths": 55, "science": 48, "english": 62, "history": 50, "cs": 58},
    {"name": "Rohan",  "maths": 72, "science": 68, "english": 75, "history": 70, "cs": 65},
    {"name": "Sneha",  "maths": 95, "science": 98, "english": 92, "history": 88, "cs": 97},
    {"name": "Karan",  "maths": 35, "science": 40, "english": 38, "history": 42, "cs": 30},
    {"name": "Meera",  "maths": 78, "science": 82, "english": 80, "history": 75, "cs": 84},
]

previous_pct = {
    "Aarav": 80.0,
    "Priya": 60.0,
    "Rohan": 65.0,
    "Sneha": 91.0,
    "Karan": 42.0,
    "Meera": 75.0,
}

Solution:

students = [
    {"name": "Aarav",  "maths": 88, "science": 92, "english": 85, "history": 78, "cs": 95},
    {"name": "Priya",  "maths": 55, "science": 48, "english": 62, "history": 50, "cs": 58},
    {"name": "Rohan",  "maths": 72, "science": 68, "english": 75, "history": 70, "cs": 65},
    {"name": "Sneha",  "maths": 95, "science": 98, "english": 92, "history": 88, "cs": 97},
    {"name": "Karan",  "maths": 35, "science": 40, "english": 38, "history": 42, "cs": 30},
    {"name": "Meera",  "maths": 78, "science": 82, "english": 80, "history": 75, "cs": 84},
]

previous_pct = {
    "Aarav": 80.0, "Priya": 60.0, "Rohan": 65.0,
    "Sneha": 91.0, "Karan": 42.0, "Meera": 75.0,
}

subjects   = ["maths", "science", "english", "history", "cs"]
max_marks  = 500
processed  = []

for s in students:
    total = sum(s[sub] for sub in subjects)
    pct   = round((total / max_marks) * 100, 1)

    if pct >= 85:
        grade = "Distinction"
    elif pct >= 60:
        grade = "First Class"
    elif pct >= 40:
        grade = "Pass"
    else:
        grade = "Fail"

    improved = pct > previous_pct.get(s["name"], 0)
    processed.append((s["name"], total, pct, grade, improved))

# Sort by percentage descending
processed.sort(key=lambda x: x[2], reverse=True)

print("=" * 65)
print(f"{'Rank':<5} {'Name':<8} {'Total':>6} {'Pct':>7} {'Grade':<13} {'Trend'}")
print("=" * 65)

for rank, (name, total, pct, grade, improved) in enumerate(processed, start=1):
    trend = "Up" if improved else "Down"
    print(f"{rank:<5} {name:<8} {total:>6}/500 {pct:>6}% {grade:<13} {trend}")

print("=" * 65)

Quick Reference

String

s = "hello"
s[0]                    # index
s[1:4]                  # slice
s[::-1]                 # reverse
len(s)                  # length
s.upper()               # uppercase
s.lower()               # lowercase
s.strip()               # remove leading/trailing whitespace
s.replace("l", "r")     # replace occurrences
s.split(" ")            # split into list
" ".join(["a", "b"])    # join list into string
s.startswith("he")      # check prefix
s.endswith("lo")        # check suffix
s.count("l")            # count occurrences
"l" in s                # membership check
s.isalpha()             # all letters?
s.isdigit()             # all digits?
s.isalnum()             # all letters or digits?

List

lst = [1, 2, 3]
lst.append(4)           # add to end
lst.insert(1, 99)       # insert at index
lst.remove(2)           # remove first occurrence
lst.pop()               # remove and return last
lst.pop(0)              # remove and return at index
lst.sort()              # sort in place
lst.reverse()           # reverse in place
lst.index(99)           # find index of value
lst.count(3)            # count occurrences
lst.copy()              # shallow copy
lst[1:3]                # slicing
lst[::-1]               # reversed copy
[x*2 for x in lst]      # list comprehension

Tuple

t = (1, 2, 3)
t[0]                    # access (no modify)
a, b, c = t             # unpack
t.count(1)              # count occurrences
t.index(2)              # find index
t1 + t2                 # concatenate (new tuple)

Dictionary

d = {"a": 1}
d["a"]                  # access
d["b"] = 2              # add / update
del d["a"]              # delete
d.get("x", 0)           # safe access with default
d.setdefault("y", 5)    # add only if missing
d.keys()                # all keys
d.values()              # all values
d.items()               # all key-value pairs
d.pop("a")              # remove and return
{k: v for k, v in d.items()}  # dict comprehension

Set

s = {1, 2, 3}
s.add(4)                # add element
s.remove(2)             # remove (error if missing)
s.discard(9)            # remove (no error)
s.pop()                 # remove arbitrary element
s1 | s2                 # union
s1 & s2                 # intersection
s1 - s2                 # difference
s1 ^ s2                 # symmetric difference
s1.issubset(s2)         # check subset
s1.issuperset(s2)       # check superset
frozenset(s)            # immutable version

When to Use Which

CollectionUse when
StringText data, characters, immutable sequences
ListOrder matters, duplicates allowed, items change
TupleFixed data, function return values, dict keys
DictionaryFast lookup by key, key-value relationships
SetUniqueness, fast membership check, set math

Made with care for Codeverra learners | codeverra.com