9. Lists
Higher Secondary · Computer Science · Science Stream

Lists

A list is an ordered, heterogeneous, dynamic, and mutable collection of elements stored under a single variable. This chapter covers creating and indexing lists, slicing, mutability and references, concatenation, built-in list functions, traversal, and applications such as linear search, matrix representation, matrix addition, and reversing a list with recursion.

9.2 – 9.3 · Live Tool

List Index & Slice Lab

Type a comma-separated list and a Python indexing or slicing expression — [2], [-1], [1:4], [-3:], [::-1], [2:7:2] — and watch the ruler highlight exactly which elements get selected.

Try Indexing / Slicing

● live
Enter a comma-separated list and an expression like [start:end:step], then press Run.
Try list: red,blue,green,yellow,purple · expressions: [2:] · [:3] · [-3:-1] · [9:0:-2] — highlighted cells show what gets selected; amber numbers are negative indices.
9.1

Creating List

A data structure is the method of organising, managing, and storing data for easy access and modification. Python provides several built-in data structures such as lists, tuples, dictionaries, and sets. A list is created by enclosing its elements within square brackets [], separated by commas.

list_name = [element1, element2, …] >>>scores=[85, 92, 78, 96, 88]

Ordered

Lists are ordered sequences — elements stay in the order they are added, and each element can be retrieved using its index (starting from 0).

Heterogeneous

A list can store values of different data types — numeric, boolean, strings, or even other lists, tuples, and dictionaries.

Dynamic

The size of a list can grow or shrink as needed — elements can be added or removed after creation.

Mutable

Elements can be changed, added, or removed after the list is created — unlike strings, which are immutable.

>>>fruits = ["apple", "banana", "orange", "grape"] >>>my_bag = ["banana", 2, False, 7.25, "juice"] # Nested list — a list holding other lists as elements >>>nested_list = [ [15, 4, 19, 84], ["Kasaragod", "Cherthala", "Mannarkkad"], [2.5, 2.25, 4.2] ]

Whenever a value is created, an object is formed in memory, and a list actually stores references to those objects rather than the values directly. Python keeps track of how many references point to each object and automatically removes objects that are no longer referenced. A list holding other lists as elements is called a nested list — useful for representing tables, grids, and matrices.

9.2

Accessing List Elements

Elements of a list are accessed using their index values: list_name[index]. Indexing starts from 0. Negative indices count from the end of the list, where -1 is always the last element.

Positive index01234
fruitsapplebananaorangegrape—
Negative index-4-3-2-1—
>>>print(fruits[0]) apple >>>print(fruits[2]) orange >>>print(fruits[5]) Traceback (most recent call last): IndexError: list index out of range # Negative indexing >>>L = [10,20,30,40,50] >>>L[-1] 50 >>>L[-2] 40 >>>L[-5] 10

Trying to access an index that does not exist raises an IndexError. Negative indices make it easy to access elements from the end of a list without needing to know its length.

9.3

List Slicing

Slicing extracts a specific portion of a list by specifying a range of indices: list_name[start:end:step]. The slice returns elements from start up to, but not including, end.

>>>colours = ["red", "blue", "green", "yellow", "purple"] >>>colours[1:4] ['blue', 'green', 'yellow'] # start / end omitted >>>colours[:3] ['red', 'blue', 'green'] >>>colours[2:] ['green', 'yellow', 'purple'] >>>colours[:] ['red', 'blue', 'green', 'yellow', 'purple'] # negative indices in slicing >>>colours[-3:4] ['green', 'yellow'] >>>colours[-3:] ['green', 'yellow', 'purple']

Replacing a Slice

>>>L2 = [5, 10, 15, 20, 25] >>>L2[1:4] = [100,200,300] >>>print(L2) [5, 100, 200, 300, 25]

Sliced replacement works because lists are mutable — Python allows a specific portion of the list to be updated directly using slicing, changing the original list in place.

Slicing with Step Value

start

The index where the slice begins. If omitted, the slice begins from the start of the list.

end

The index where the slice stops (this element is not included). If omitted, the slice continues to the end of the list.

step

How many positions to move each time. A negative step slices in the reverse direction.

>>>numbers=[11,12,13,14,15,16,17,18,19,20] >>>numbers[2:7:2] [13, 15, 17] # negative step — reverse direction >>>numbers[9:0:-2] [20, 18, 16, 14, 12]
9.4

Mutability of List

Every variable name is just a reference (label) pointing to an object stored in memory. Lists are mutable — their elements can be changed after creation, and changes made through one reference are visible through every reference to the same object.

>>>L1 = [10, 20, 30] >>>L2 = L1 # L2 refers to the SAME list object as L1 >>>L1[0] = 100 >>>print(L2) [100, 20, 30] # change via L1 is reflected in L2 too
>>>L1 = [10, 20, 30] # Original list >>>L2 = L1[0:2] # Slice extraction creates a NEW list [10, 20] >>>L2[0] = 100 # Modification affects only L2 >>>print(L1) # L1 remains unchanged [10, 20, 30] >>>print(L2) [100, 20]

Assigning L2 = L1 makes both names point to the same list object — no new object is created, so modifying one modifies the other. But extracting a slice into a new variable creates a brand-new list object, so changes to the copy do not affect the original.

9.5

Concatenation of Lists

Concatenation means joining two or more lists into a single list without altering the originals. The + operator is used to concatenate lists in Python.

>>>L1 = [10,20,30] >>>L2 = [40,50] >>>L3 = L1+L2 >>>L3 [10, 20, 30, 40, 50] >>>classA = ["Asha", "Binu", "Chitra"] >>>classB = ["Deepa", "Asha", "Fahad"] >>>all_students = classA + classB >>>print(all_students) ['Asha', 'Binu', 'Chitra', 'Deepa', 'Asha', 'Fahad']

Using + creates a new list object — L1 and L2 remain unchanged, while L3 refers to a new memory location. Duplicate elements present in both lists (like "Asha" above) are preserved during concatenation.

9.6 · Live Tool

List Functions and Operations

Python provides membership operators and built-in methods to add, remove, or query elements of a list.

Membership Operators — in / not in

>>>solar_planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"] >>>"Uranus" in solar_planets True >>>"Pluto" in solar_planets False >>>water_elements = ["Hydrogen", "Oxygen"] >>>'Carbon' not in water_elements True >>>'Oxygen' not in water_elements False

Try a List Method

● live
Pick a method, fill in the base list and argument(s), then press Run.
insert() needs two args, comma-separated: 2,black (index, value) · pop()/del use one index (blank pop() removes the last item) · remove()/count()/index() need one value.
Function / MethodDescriptionExample
append()Adds an item to the end of the list, increasing its sizefibonacci.append(8)
insert()Inserts an element at a specified index in the listcolours.insert(2, "black")
pop()Removes and returns an element at a given position (last, if none specified)colours.pop(3)
remove()Removes the first occurrence of a specified elementcolours.remove("blue")
len()Returns the number of elements in a listlen(colours)
delDeletes an element or slice without returning it; can also delete the whole listdel colours[3]
9.7

Traversing List

Traversal means visiting each element of a list to perform operations such as counting, updating, or checking conditions.

9.7.1 Direct Traversal

expenses = [120, 250, 80, 150, 200] print("Expenses:") for expense in expenses: print (expense) Output: Expenses: 120 250 80 150 200

The simplest way to read or process items — a for loop assigns each element in turn to a variable, ideal when we only need to read or check elements.

9.7.2 Index-Based Traversal

marks = [55, 72, 38, 90, 25, 17, 48, 33, 27, 12, 60] pass_mark = 25 for i in range(len(marks)): if marks[i] < pass_mark: print("Sl.No.", i+1, "Failed") Output: Sl.No. 6 Failed Sl.No. 10 Failed

Uses range(len(list)) to generate index values, giving direct control over each element — needed when the list must be modified or updated while traversing.

def update_price(price_list): for i in range(len(price_list)): if price_list[i] < 200: price_list[i] = price_list[i] + price_list[i] * 0.10 elif price_list[i] >= 500: price_list[i] = price_list[i] - price_list[i] * 0.05 return price_list price = [200, 300, 75, 110, 300, 475, 500, 150, 600, 525] new_price = update_price(price) Output: Initial Prices: [200, 300, 75, 110, 300, 475, 500, 150, 600, 525] Updated Prices: [200, 300, 82.5, 121.0, 300, 475, 475.0, 165.0, 570.0, 498.75]

Prices below ₹200 are increased by 10%; prices ₹500 or above are reduced by 5%; all other prices remain unchanged — a function performing calculations directly on list items using index-based traversal.

9.8

Applications of List

Lists support real-world programming needs — from linear search to representing matrices and illustrating recursion.

9.8.1 Linear Search

Linear (sequential) search checks elements one by one, starting from the first, until the target is found or the list ends.

def linear_search(LIST, ITEM): LOC = -1 for i in range(len(LIST)): if LIST[i] == ITEM: LOC = i break return LOC # Main Program LOC = linear_search(LIST, ITEM) if LOC == -1: print("Item not found in the list.") else: print(f"Item found at position {LOC + 1}") Run: List: 23, 0, 76, 987, 234, 786, 34 Enter the element to be searched: 234 Item found at position 5

9.8.2 Matrix Representation

A matrix is a rectangular arrangement of values in rows and columns. Nested lists represent a matrix — each inner list is a row, and elements aligned vertically across the inner lists form the columns. Order is row × column (m × n). An element is accessed as matrix[row][column].

>>> matrix = [[1,2,3],[4,5,6],[7,8,9]] >>> for row in matrix: for item in row: print(item, end=" ") print() 1 2 3 4 5 6 7 8 9 >>> matrix[0][2] # First row, third column 3 >>> matrix[2][1] # Third row, second column 8

The outer loop iterates through each row; the inner loop through each element within that row. When all inner lists contain the same number of elements, the nested list forms a valid matrix.

9.8.3 Matrix Addition

Two matrices can be added only if they have the same order (same number of rows and columns) — they must be conformable for addition. Corresponding elements (same row and column position) are added to form the result matrix.

def add_matrices(mat1, mat2): rows = len(mat1) cols = len(mat1[0]) result = [] for i in range(rows): row = [] for j in range(cols): row.append(mat1[i][j] + mat2[i][j]) result.append(row) return result if len(mat1) == len(mat2) and len(mat1[0]) == len(mat2[0]): result = add_matrices(mat1, mat2) else: print("Addition is not possible: matrices are not conformable for addition.") Example: mat1 = [[-1,-2],[-3,-4]] mat2 = [[-4,-3],[-2,-1]] Result of Matrix Addition: -5 -5 -5 -5

9.8.4 Processing Diagonal Elements of a Matrix

Diagonal elements run from the top-left corner to the bottom-right corner — positions where the row index equals the column index, i.e. [i][i]. Diagonal elements exist only in square matrices (rows = columns).

def print_diagonal(matrix): print("Diagonal Elements:") for i in range(len(matrix)): print(matrix[i][i], end=" ") Generated Matrix (3 x 3): 2 42 1 49 44 38 17 34 22 Diagonal Elements: 2 44 22

Diagonal elements are useful for finding the trace of a matrix, simplifying calculations, and identifying special matrix types such as symmetric matrices.

9.8.5 Reverse a List Using Recursion

def reverse_list(nums): if len(nums) <= 1: return nums # Base case # Recursive case: return reverse_list(nums[1:]) + [nums[0]] numbers = [1, 10, 100, 1000, 10000, 100000] Original list: [1, 10, 100, 1000, 10000, 100000] Reversed list: [100000, 10000, 1000, 100, 10, 1]

If the list has zero or one element, it is returned as-is (base case). Otherwise, the function calls itself on nums[1:] (everything except the first element) and appends nums[0] to the end of that reversed result — building the reversed list one recursive call at a time.

Let Us Do

Quick Recap

Tap a question to reveal the answer.

For numbers = [5, 10, 15, 20, 25, 30, 35, 40], what does numbers[1:-2] give?

[10, 15, 20, 25, 30] — the slice starts at index 1 and stops just before index -2 (i.e. before the 7th element, 35).

What does numbers[::-2] give for the same list?

[40, 30, 20, 10] — start and end are omitted, so Python begins at the last element and moves backward, taking every second element.

Why does L2 = L1 followed by L1[0] = 100 also change L2?

Because a list variable is just a reference to a list object in memory. L2 = L1 makes both names point to the same object — no new list is created — so modifying the object through one name is visible through the other.

How is a copy made that does not affect the original list?

By extracting a slice, e.g. L2 = L1[0:2]. Slice extraction creates a brand-new list object, so changes made to L2 afterwards do not affect L1.

What is the difference between remove() and pop()?

remove(value) deletes the first occurrence of the given value and returns nothing. pop(index) deletes the element at the given position (last element if no index given) and returns that removed value.

Why do classA + classB keep the element "Asha" twice if it appears in both lists?

Concatenation with + simply joins all elements from both lists in order, without checking for or removing duplicates. Both occurrences of "Asha" are preserved in the new, combined list.

Two matrices are 2×3 and 3×2 in order. Can they be added? Why or why not?

No. Matrix addition requires both matrices to have the same order — the same number of rows and the same number of columns — so they are "conformable" for addition. A 2×3 and a 3×2 matrix are not conformable.

In a nested list representing a 3×3 matrix, how would you access the element in the 2nd row, 3rd column?

matrix[1][2] — row and column numbering starts from 0 in Python, so the 2nd row is index 1 and the 3rd column is index 2.

In the recursive function reverse_list(nums), what is the base case and why is it needed?

The base case is if len(nums) <= 1: return nums. Without it, the function would keep calling itself on shorter and shorter slices forever (infinite recursion); the base case stops the recursion once the list has zero or one element, which is trivially already "reversed".

What does del colours[3] do, compared to colours.pop(3)?

Both remove the element at index 3, but del is a statement that does not return the removed value, while pop(3) is a method that removes and returns the removed element, so it can be captured in a variable.