Python Advanced Practice Programs (with Output)
input() show the sample value typed after each prompt, for example Enter a number: 29.How to use this page: read the explanation, type the code yourself (do not just copy), run it, then change the input and predict the new output before running again. For practical exams, be ready to explain the time complexity and one alternative approach. New to Python? Start with the Python course; for Pandas and NumPy in depth, see the 60-day Data Science course.
Searching and Sorting
Linear Search
Checks every element from left to right. Works on unsorted lists. Time complexity: O(n).
a = [10, 25, 7, 40, 18]
x = int(input("Number to search: "))
for i in range(len(a)):
if a[i] == x:
print("Found at index", i)
break
else:
print("Not found")
Number to search: 7 Found at index 2
Binary Search
Works only on a sorted list. It checks the middle element and discards half of the list each step. Time complexity: O(log n).
a = [10, 20, 30, 40, 50]
x = int(input("Number to search: "))
low, high = 0, len(a) - 1
while low <= high:
mid = (low + high) // 2
if a[mid] == x:
print("Found at index", mid)
break
elif x < a[mid]: high = mid - 1
else: low = mid + 1
else:
print("Not found")
Number to search: 40 Found at index 3
Bubble Sort
Compares neighbours and swaps them when out of order. After each pass the largest remaining value “bubbles” to the end, so the inner loop shrinks by i. Time complexity: O(n²).
a = [5, 1, 4, 2, 8]
for i in range(len(a)):
for j in range(len(a) - 1 - i):
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
print(a)
[1, 2, 4, 5, 8]
Selection Sort
Finds the smallest value in the unsorted part and swaps it to the front. It makes at most n−1 swaps, useful when swapping is costly. Time complexity: O(n²).
a = [64, 25, 12, 22, 11]
for i in range(len(a)):
small = i
for j in range(i + 1, len(a)):
if a[j] < a[small]:
small = j
a[i], a[small] = a[small], a[i]
print(a)
[11, 12, 22, 25, 64]
Insertion Sort
Takes each value (key) and shifts larger values one place right until the key’s correct position is found – like arranging playing cards in your hand. Fast for nearly sorted lists. Time complexity: O(n²), best O(n).
a = [5, 2, 4, 6, 1, 3]
for i in range(1, len(a)):
key = a[i]
j = i - 1
while j >= 0 and a[j] > key:
a[j + 1] = a[j]
j -= 1
a[j + 1] = key
print(a)
[1, 2, 3, 4, 5, 6]
Stack and Queue
Stack using List
Stack is LIFO (Last In, First Out): append() pushes on top and pop() removes from the top. Time complexity: push/pop O(1).
stack = []
stack.append(10)
stack.append(20)
stack.append(30)
print("Stack:", stack)
print("Deleted:", stack.pop())
print("Stack:", stack)
Stack: [10, 20, 30] Deleted: 30 Stack: [10, 20]
Queue using deque
Queue is FIFO (First In, First Out). collections.deque removes from the front in O(1); list.pop(0) would be O(n). Time complexity: enqueue/dequeue O(1).
from collections import deque
q = deque()
q.append(10)
q.append(20)
q.append(30)
print("Queue:", list(q))
print("Deleted:", q.popleft())
print("Queue:", list(q))
Queue: [10, 20, 30] Deleted: 10 Queue: [20, 30]
Number Programs and Series
Prime Number Check
Checks divisors only up to √n. If none divides n, it is prime. The for … else runs the else part only when the loop did not break. Time complexity: O(√n).
n = int(input("Enter a number: "))
if n < 2:
print("Not Prime")
else:
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
print("Not Prime")
break
else:
print("Prime")
Enter a number: 29 Prime
Fibonacci Series
Each term is the sum of the previous two. Tuple assignment a, b = b, a + b updates both values at once without a temporary variable. Time complexity: O(n).
n = int(input("How many terms? "))
a, b = 0, 1
for i in range(n):
print(a, end=" ")
a, b = b, a + b
How many terms? 10 0 1 1 2 3 5 8 13 21 34
Arithmetic Progression (AP)
The i-th term is a + i·d (starting from i = 0). Time complexity: O(n).
a = int(input("First term: "))
d = int(input("Common difference: "))
n = int(input("Number of terms: "))
for i in range(n):
print(a + i * d, end=" ")
First term: 2 Common difference: 3 Number of terms: 6 2 5 8 11 14 17
Geometric Progression (GP)
The i-th term is a·rⁱ. ** is the power operator in Python. Time complexity: O(n).
a = int(input("First term: "))
r = int(input("Common ratio: "))
n = int(input("Number of terms: "))
for i in range(n):
print(a * r ** i, end=" ")
First term: 3 Common ratio: 2 Number of terms: 6 3 6 12 24 48 96
Pattern Programs
Three classic patterns: a right-angled star triangle, a number triangle, and an inverted triangle. "* " * i repeats the string i times. Time complexity: O(n²).
n = 5
for i in range(1, n + 1):
print("* " * i)
for i in range(1, n + 1):
print(" ".join(str(j) for j in range(1, i + 1)))
for i in range(n, 0, -1):
print("* " * i)
* * * * * * * * * * * * * * * 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 * * * * * * * * * * * * * * *
List Programs
List Operations
append adds at the end, insert at a position, remove deletes the first matching value; max and sum are built-in.
a = [10, 20, 30]
a.append(40)
a.insert(1, 15)
a.remove(20)
print("List:", a)
print("Largest:", max(a))
print("Sum:", sum(a))
List: [10, 15, 30, 40] Largest: 40 Sum: 95
List Comprehension
A short way to build a new list: [expression for x in list if condition]. Time complexity: O(n).
numbers = [1, 2, 3, 4, 5]
squares = [x * x for x in numbers]
even = [x for x in numbers if x % 2 == 0]
print(squares)
print(even)
[1, 4, 9, 16, 25] [2, 4]
Remove Duplicates (keep order)
Adds a value only if it is not already in the result. For large lists, list(dict.fromkeys(a)) does the same in O(n). Time complexity: O(n²).
a = [1, 2, 2, 3, 1, 4]
result = []
for x in a:
if x not in result:
result.append(x)
print(result)
[1, 2, 3, 4]
Dictionary Programs
Dictionary Operations
A dictionary stores key–value pairs. Assigning to a new key adds it; assigning to an existing key updates it; items() gives both.
student = {"name": "Ananya", "marks": 92}
print(student["name"])
student["grade"] = "A1"
student["marks"] = 95
for key, value in student.items():
print(key, value)
Ananya name Ananya marks 95 grade A1
Word Frequency using Dictionary
freq.get(word, 0) returns 0 for a new word, so the count starts correctly. Time complexity: O(n).
text = input("Enter text: ").split()
freq = {}
for word in text:
freq[word] = freq.get(word, 0) + 1
print(freq)
Enter text: to be or not to be
{'to': 2, 'be': 2, 'or': 1, 'not': 1}
Merge Two Dictionaries
{**a, **b} unpacks both dictionaries into a new one (Python 3.5+). In Python 3.9+ you can also write a | b.
a = {"x": 1, "y": 2}
b = {"z": 3}
c = {**a, **b}
print(c)
{'x': 1, 'y': 2, 'z': 3}
Pandas Programs
Pandas Series
A Series is a one-dimensional labelled array. The left column in the output is the index.
import pandas as pd
s = pd.Series([10, 20, 30, 40])
print(s)
print("Sum =", s.sum())
print("Average =", s.mean())
0 10 1 20 2 30 3 40 dtype: int64 Sum = 100 Average = 25.0
Pandas DataFrame and Filtering
df[df["Marks"] > 80] keeps only rows where the condition is True (boolean filtering).
import pandas as pd
data = {"Name": ["Aman", "Riya", "Kabir"], "Marks": [78, 92, 85]}
df = pd.DataFrame(data)
print(df)
print(df[df["Marks"] > 80])
Name Marks
0 Aman 78
1 Riya 92
2 Kabir 85
Name Marks
1 Riya 92
2 Kabir 85
Pandas: CSV, Missing Values and GroupBy
Reads a CSV, counts missing values per column and finds the average marks per class. The sample students.csv used here has one blank mark (Sana), so its Marks shows NaN and is ignored by mean().
Save this as students.csv in the same folder:
Name,Class,Marks
Aman,10A,78
Riya,10A,92
Kabir,10B,85
Sana,10B,
Dev,10A,66
Ira,10B,90
import pandas as pd
df = pd.read_csv("students.csv")
print(df.head())
print(df.isnull().sum())
print(df.groupby("Class")["Marks"].mean())
Name Class Marks 0 Aman 10A 78.0 1 Riya 10A 92.0 2 Kabir 10B 85.0 3 Sana 10B NaN 4 Dev 10A 66.0 Name 0 Class 0 Marks 1 dtype: int64 Class 10A 78.666667 10B 87.500000 Name: Marks, dtype: float64
NumPy Programs
NumPy Array Basics
NumPy arrays support fast vectorised maths: sum(), mean(), max() work on the whole array without a loop.
import numpy as np
a = np.array([10, 20, 30, 40])
print(a)
print("Sum =", a.sum())
print("Average =", a.mean())
print("Largest =", a.max())
[10 20 30 40] Sum = 100 Average = 25.0 Largest = 40
NumPy Matrix Addition and Multiplication
+ adds element by element; @ is true matrix multiplication (row × column).
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
print("Addition:\n", a + b)
print("Multiplication:\n", a @ b)
Addition: [[ 6 8] [10 12]] Multiplication: [[19 22] [43 50]]
NumPy Reshape and Indexing
reshape(3, 4) turns 12 values into 3 rows × 4 columns. b[1] is the second row and b[:, 1] the second column.
import numpy as np
a = np.arange(1, 13)
b = a.reshape(3, 4)
print(b)
print("Second row:", b[1])
print("Second column:", b[:, 1])
[[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] Second row: [5 6 7 8] Second column: [ 2 6 10]
Quick viva questions
- Why can binary search not be used on an unsorted list? It decides which half to discard by comparing with the middle element; that only works when the list is sorted.
- Which sorting algorithm above is fastest for an almost sorted list? Insertion sort – it needs close to n comparisons in that case.
- Why use
dequeinstead of a list for a queue?popleft()is O(1), whilelist.pop(0)shifts every element (O(n)). - What is the difference between a list and a dictionary? A list is ordered and accessed by position; a dictionary is accessed by unique keys.
- What does NaN mean in Pandas? “Not a Number” – a missing value.
isnull().sum()counts them per column. - What is the difference between
*and@for NumPy matrices?*multiplies element by element;@does matrix multiplication.
