CBSE Class 11 Computer Science Chapter 9 — Lists
Chapter Introduction
A list is one of the most versatile and frequently used data structures in Python. Unlike a string, which holds only characters and cannot be changed after creation, a list can hold items of any type and can be modified at any time. Lists are ordered, mutable, and allow duplicate elements. They are the Python equivalent of arrays in other languages, but far more flexible because they can store mixed data types.
In this chapter, you will learn how to create lists, access and modify their elements, use built-in methods, write list comprehensions, work with nested lists, and solve common programming problems using lists. Mastering lists is essential for the CBSE Class 11 Computer Science exam and for all future Python programming.
Key Definitions
| Term | Definition |
|---|---|
| List | An ordered, mutable sequence of items enclosed in square brackets []. |
| Index | The position number of an item in a list. Starts from 0. |
| Negative Index | Indexing from the end of the list. -1 is the last item, -2 is second-last, etc. |
| Slicing | Extracting a portion of a list using the syntax list[start:stop:step]. |
| Mutable | A data type whose contents can be changed after creation. Lists are mutable. |
| List Comprehension | A concise one-line syntax to create a list from an iterable. |
| Nested List | A list that contains other lists as its elements. |
| Shallow Copy | A copy of a list that creates a new list object but shares references to the inner elements. |
| Deep Copy | A copy that recursively copies all objects, creating fully independent duplicates. |
Detailed Concepts
1. Creating Lists
There are several ways to create a list in Python:
Using list literals (square brackets):
# List of integers
numbers = [10, 20, 30, 40, 50]
# List of strings
fruits = ["apple", "banana", "cherry"]
# Mixed data types
mixed = [1, "hello", 3.14, True, None]
# Empty list
empty = []
Using the list() constructor from a range:
# Create a list from range()
nums = list(range(1, 11))
print(nums) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# List of even numbers
evens = list(range(0, 21, 2))
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Creating a list from a string:
chars = list("Python")
print(chars) # ['P', 'y', 't', 'h', 'o', 'n']
Creating a nested list:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(matrix) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2. Accessing Elements
Each item in a list has a position called an index. Python supports both positive and negative indexing.
Positive indexing (starts from 0):
colors = ["red", "green", "blue", "yellow"]
print(colors[0]) # red
print(colors[2]) # blue
Negative indexing (starts from -1):
colors = ["red", "green", "blue", "yellow"]
print(colors[-1]) # yellow
print(colors[-3]) # green
IndexError:
colors = ["red", "green", "blue"]
# print(colors[5]) # Raises IndexError: list index out of range
Always ensure the index is within the valid range: 0 to len(list) - 1 for positive indexing, or -1 to -len(list) for negative indexing.
3. List Slicing
Slicing extracts a sub-list. The general syntax is:
- start — index where slicing begins (default 0)
- stop — index where slicing ends (exclusive, default end of list)
- step — increment between indices (default 1)
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(nums[2:7]) # [2, 3, 4, 5, 6]
print(nums[:5]) # [0, 1, 2, 3, 4]
print(nums[5:]) # [5, 6, 7, 8, 9]
print(nums[::2]) # [0, 2, 4, 6, 8] (every second element)
print(nums[1::3]) # [1, 4, 7]
print(nums[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (reverse)
print(nums[-3:]) # [7, 8, 9]
print(nums[2:8:2]) # [2, 4, 6]
Key point: slicing always returns a new list. The original list is not modified.
4. List Operations
Concatenation (+): Joins two lists to create a new list.
a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
print(c) # [1, 2, 3, 4, 5, 6]
*Repetition ():** Repeats the list elements.
a = [1, 2]
print(a * 3) # [1, 2, 1, 2, 1, 2]
Membership (in / not in): Checks whether an item exists in the list.
fruits = ["apple", "banana", "cherry"]
print("banana" in fruits) # True
print("mango" not in fruits) # True
print("mango" in fruits) # False
5. List Methods
| Method | Syntax | Description | Example |
|---|---|---|---|
append() | list.append(item) | Adds an item to the end of the list | [1,2].append(3) -> [1,2,3] |
extend() | list.extend(iterable) | Adds all items from an iterable to the end | [1,2].extend([3,4]) -> [1,2,3,4] |
insert() | list.insert(index, item) | Inserts an item at the given index | [1,3].insert(1,2) -> [1,2,3] |
remove() | list.remove(item) | Removes the first occurrence of the item | [1,2,1].remove(1) -> [2,1] |
pop() | list.pop(index) | Removes and returns item at index (default -1) | [1,2,3].pop() -> returns 3 |
clear() | list.clear() | Removes all items from the list | [1,2].clear() -> [] |
index() | list.index(item) | Returns the index of the first occurrence | [1,2,3].index(2) -> 1 |
count() | list.count(item) | Returns the number of occurrences | [1,2,1].count(1) -> 2 |
sort() | list.sort() | Sorts the list in place (ascending by default) | [3,1,2].sort() -> [1,2,3] |
reverse() | list.reverse() | Reverses the list in place | [1,2,3].reverse() -> [3,2,1] |
copy() | list.copy() | Returns a shallow copy of the list | a = [1,2]; b = a.copy() |
Note on sorted() function (not a method): Unlike sort(), sorted() returns a new sorted list and does not modify the original.
nums = [3, 1, 4, 1, 5, 9]
sorted_nums = sorted(nums)
print(sorted_nums) # [1, 1, 3, 4, 5, 9]
print(nums) # [3, 1, 4, 1, 5, 9] (original unchanged)
# Descending order
print(sorted(nums, reverse=True)) # [9, 5, 4, 3, 1, 1]
Code examples for key methods:
# append - adds one item
fruits = ["apple", "banana"]
fruits.append("cherry")
print(fruits) # ['apple', 'banana', 'cherry']
# extend - adds multiple items
fruits = ["apple", "banana"]
fruits.extend(["cherry", "date"])
print(fruits) # ['apple', 'banana', 'cherry', 'date']
# insert - adds at specific position
fruits = ["apple", "cherry"]
fruits.insert(1, "banana")
print(fruits) # ['apple', 'banana', 'cherry']
# remove - removes first occurrence
nums = [1, 2, 3, 2, 4]
nums.remove(2)
print(nums) # [1, 3, 2, 4]
# pop - removes and returns
nums = [10, 20, 30, 40]
removed = nums.pop(1)
print(removed) # 20
print(nums) # [10, 30, 40]
# pop without argument removes last
last = nums.pop()
print(last) # 40
print(nums) # [10, 30]
# sort and reverse
nums = [5, 2, 8, 1, 9]
nums.sort()
print(nums) # [1, 2, 5, 8, 9]
nums.reverse()
print(nums) # [9, 8, 5, 2, 1]
# count and index
nums = [1, 2, 3, 2, 4, 2]
print(nums.count(2)) # 3
print(nums.index(2)) # 1 (first occurrence)
6. Mutable Nature of Lists
Lists are mutable, meaning you can change their content after creation. When you modify a list, the same list object is updated — it does not create a new object.
nums = [1, 2, 3, 4, 5]
print(id(nums)) # e.g., 140234567890240
# Modify an element
nums[2] = 99
print(nums) # [1, 2, 99, 4, 5]
print(id(nums)) # Same as before — same object
# Modify a slice
nums[1:3] = [20, 30]
print(nums) # [1, 20, 30, 4, 5]
This is fundamentally different from strings, which are immutable:
s = "hello"
# s[0] = "H" # Raises TypeError: 'str' object does not support item assignment
7. List Comprehensions
List comprehension is a powerful and concise way to create lists. It replaces multi-line for loops with a single expression.
Syntax:
[expression for item in iterable if condition]
The if condition part is optional.
Examples:
# Squares of numbers from 1 to 10
squares = [x**2 for x in range(1, 11)]
print(squares) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# Even numbers from 1 to 20
evens = [x for x in range(1, 21) if x % 2 == 0]
print(evens) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# Convert strings to uppercase
words = ["hello", "world"]
upper = [w.upper() for w in words]
print(upper) # ['HELLO', 'WORLD']
# Flatten a nested list
nested = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [item for row in nested for item in row]
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# List of (number, square) tuples
pairs = [(x, x**2) for x in range(1, 6)]
print(pairs) # [(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
# Filter positive numbers
nums = [-3, 5, -1, 8, 0, 2, -7]
positives = [n for n in nums if n > 0]
print(positives) # [5, 8, 2]
8. Nested Lists
A nested list is a list whose elements are themselves lists. They are commonly used to represent matrices or tables.
Creating a nested list:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
Accessing elements in a nested list:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(matrix[0]) # [1, 2, 3] (first row)
print(matrix[1][2]) # 6 (second row, third column)
print(matrix[2][0]) # 7 (third row, first column)
Iterating over a nested list:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Print each row
for row in matrix:
print(row)
# [1, 2, 3]
# [4, 5, 6]
# [7, 8, 9]
# Print each element
for row in matrix:
for item in row:
print(item, end=" ")
print()
# 1 2 3
# 4 5 6
# 7 8 9
9. Traversing a List
Using a for loop:
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
Using a while loop with index:
fruits = ["apple", "banana", "cherry"]
i = 0
while i < len(fruits):
print(fruits[i])
i += 1
Using enumerate() to get both index and value:
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry
# enumerate with a custom start index
for index, fruit in enumerate(fruits, start=1):
print(f"{index}: {fruit}")
# 1: apple
# 2: banana
# 3: cherry
10. Copying Lists
Assignment does NOT create a copy — both variables point to the same list object:
a = [1, 2, 3]
b = a
b[0] = 99
print(a) # [99, 2, 3] — 'a' is also modified!
Shallow copy creates a new list object but inner elements are shared:
a = [1, 2, 3]
b = a.copy() # or b = a[:] or b = list(a)
b[0] = 99
print(a) # [1, 2, 3] — 'a' is unchanged
Shallow copy limitation with nested lists:
a = [[1, 2], [3, 4]]
b = a.copy()
b[0][0] = 99
print(a) # [[99, 2], [3, 4]] — 'a' IS modified because inner lists are shared
Deep copy creates a fully independent copy:
import copy
a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)
b[0][0] = 99
print(a) # [[1, 2], [3, 4]] — 'a' is unchanged
print(b) # [[99, 2], [3, 4]]
11. Common List Programs
Find maximum and minimum:
nums = [34, 12, 67, 5, 89, 23]
print(max(nums)) # 89
print(min(nums)) # 5
# Manual approach (without built-in)
maximum = nums[0]
for n in nums:
if n > maximum:
maximum = n
print(maximum) # 89
Remove duplicates from a list:
nums = [1, 2, 3, 2, 4, 1, 5, 3]
unique = []
for n in nums:
if n not in unique:
unique.append(n)
print(unique) # [1, 2, 3, 4, 5]
# Using set (faster, but loses order)
unique2 = list(set(nums))
print(sorted(unique2)) # [1, 2, 3, 4, 5]
Merge two sorted lists:
a = [1, 3, 5, 7]
b = [2, 4, 6, 8]
merged = sorted(a + b)
print(merged) # [1, 2, 3, 4, 5, 6, 7, 8]
# Manual merge without sort
i = j = 0
result = []
while i < len(a) and j < len(b):
if a[i] < b[j]:
result.append(a[i])
i += 1
else:
result.append(b[j])
j += 1
result.extend(a[i:])
result.extend(b[j:])
print(result) # [1, 2, 3, 4, 5, 6, 7, 8]
Linear search:
def linear_search(lst, target):
for i in range(len(lst)):
if lst[i] == target:
return i
return -1
nums = [10, 20, 30, 40, 50]
print(linear_search(nums, 30)) # 2
print(linear_search(nums, 99)) # -1
Count frequency of each element:
nums = [1, 2, 3, 2, 1, 3, 3, 4]
freq = {}
for n in nums:
freq[n] = freq.get(n, 0) + 1
print(freq) # {1: 2, 2: 2, 3: 3, 4: 1}
12. Comparison: List vs String
| Feature | List | String |
|---|---|---|
| Syntax | Square brackets [] | Quotes '' or "" |
| Mutability | Mutable | Immutable |
| Element types | Any (mixed types allowed) | Only characters |
| Modification | lst[0] = 10 works | s[0] = 'H' raises TypeError |
| Methods | append(), insert(), remove(), etc. | upper(), replace(), split(), etc. |
| Iteration | for item in lst: | for ch in s: |
| Concatenation | lst1 + lst2 | s1 + s2 |
| Slicing | Returns a new list | Returns a new string |
| Conversion | list("abc") -> ['a','b','c'] | str(['a','b','c']) -> string representation |
Common Mistakes
1. Using assignment to copy a list: b = a does not create a copy. Both variables reference the same list. Use b = a.copy() or b = a[:] instead.
2. Modifying a list while iterating over it: Removing or adding items during a for-loop can skip elements or cause IndexError. Iterate over a copy or build a new list instead.
3. Confusing append() with extend(): append([4, 5]) adds a nested list as a single element. extend([4, 5]) adds each item individually.
4. Forgetting that slicing returns a new list: a[1:3] creates a new list object. Modifying it does not affect the original.
5. Using remove() when the item does not exist: remove() raises a ValueError if the item is not found. Check membership with in first, or use a try-except block.
6. Ignoring that sort() returns None: new_list = old_list.sort() sets new_list to None. Use sorted() if you need a new sorted list.
7. Single-element tuple vs single-element list confusion: A single-element tuple needs a comma (5,), but a single-element list works fine [5]. This matters when converting between types.
8. Index out of range: Accessing lst[len(lst)] is invalid. The last valid index is len(lst) - 1.
Exam Tips
1. Know the difference between sort() and sorted(): sort() modifies the original list and returns None. sorted() returns a new list and leaves the original unchanged. This is a very common exam question.
2. Understand negative indexing thoroughly: Practice accessing elements using negative indices. Be ready to predict the output of slicing expressions with negative indices.
3. Master list comprehensions: Be able to write and read list comprehensions. The exam often asks you to convert a for-loop into a list comprehension or predict the output of a given comprehension.
4. Remember method return values: Methods like append(), insert(), sort(), and reverse() return None — they modify the list in place. Do not assign their result to a variable.
5. Practice nested list access: Know how to access elements like matrix[i][j]. The exam may ask you to print a specific element or iterate over a matrix.
6. Know the difference between shallow copy and deep copy: Understand when copy() is sufficient and when deepcopy() is needed (for nested lists).
7. Write output predictions carefully: Trace through list operations step by step. Many exam questions show a sequence of list method calls and ask for the final state of the list.
8. Know the pop() method details: pop() without an argument removes and returns the last element. pop(index) removes and returns the element at the given index. This distinction appears in board exams.
Quick Revision Notes
- A list is an ordered, mutable sequence that allows duplicate elements and mixed data types.
- Lists are created using
[]or thelist()constructor. - Indexing starts at 0; negative indices count from the end starting at -1.
- Slicing syntax:
list[start:stop:step]—startis inclusive,stopis exclusive. +concatenates lists;*repeats list elements;inchecks membership.append()adds one item to the end;extend()adds all items from an iterable.insert(i, item)inserts at positioni;remove(item)removes first occurrence.pop()removes and returns the last item;pop(i)removes and returns item at indexi.sort()sorts in place and returnsNone;sorted()returns a new sorted list.reverse()reverses in place; slicing[::-1]creates a reversed copy.copy()creates a shallow copy; usecopy.deepcopy()for nested lists.- List comprehension:
[expr for item in iterable if condition]. - Assignment (
b = a) does not copy — both variables reference the same object. len(list)returns the number of elements;count(item)returns occurrences of item.index(item)returns the first position of item; raisesValueErrorif not found.- Nested lists are accessed using double indexing:
matrix[row][col]. - Use
enumerate()to loop with both index and value. - Always reserve index range: valid indices are
0tolen(lst) - 1.
