Lesson 8 of 2014 min read

Lists

Share:WhatsAppLinkedIn

Prerequisites: Variables, data types, operators, loops, conditionals, strings


1. What is a List?

A list is an ordered, mutable collection of items. Items can be of different data types. Lists are one of the most versatile data structures in Python.

# A list can hold different types
mixed = [1, "hello", 3.14, True]

2. Creating Lists

2.1 Using Square Brackets []

empty = []
numbers = [1, 2, 3, 4, 5]
names = ["Alice", "Bob", "Charlie"]
mixed = [1, "two", 3.0, True]
print(numbers)
print(names)

Output:

[1, 2, 3, 4, 5]
['Alice', 'Bob', 'Charlie']

2.2 Using list Function

# Convert string to list
L1 = list("Hello")
print(L1)

# Convert range to list
L2 = list(range(1, 6))
print(L2)

# Convert tuple to list
L3 = list((10, 20, 30))
print(L3)

Output:

['H', 'e', 'l', 'l', 'o']
[1, 2, 3, 4, 5]
[10, 20, 30]

2.3 Using List Comprehension

squares = [x**2 for x in range(1, 6)]
print(squares)

evens = [x for x in range(1, 11) if x % 2 == 0]
print(evens)

Output:

[1, 4, 9, 16, 25]
[2, 4, 6, 8, 10]

3. Indexing

3.1 Positive Indexing (starts at 0)

L = [10, 20, 30, 40, 50]
print(L[0]) # 10
print(L[2]) # 30
print(L[4]) # 50

Output:

10
30
50

3.2 Negative Indexing (starts at -1 from the end)

L = [10, 20, 30, 40, 50]
print(L[-1]) # 50
print(L[-3]) # 30
print(L[-5]) # 10

Output:

50
30
10

3.3 Index Table

List: 10 20 30 40 50
Index: 0 1 2 3 4
Neg: -5 -4 -3 -2 -1

4. Slicing: L[start:stop:step]

Works exactly like string slicing.

L = [10, 20, 30, 40, 50, 60, 70]

print(L[2:5]) # [30, 40, 50]
print(L[:3]) # [10, 20, 30]
print(L[3:]) # [40, 50, 60, 70]
print(L[::2]) # [10, 30, 50, 70]
print(L[::-1]) # [70, 60, 50, 40, 30, 20, 10] (reversed)
print(L[1:6:2]) # [20, 40, 60]

Output:

[30, 40, 50]
[10, 20, 30]
[40, 50, 60, 70]
[10, 30, 50, 70]
[70, 60, 50, 40, 30, 20, 10]
[20, 40, 60]

5. List Operations

5.1 Concatenation (+)

L1 = [1, 2, 3]
L2 = [4, 5, 6]
L3 = L1 + L2
print(L3)

Output:

[1, 2, 3, 4, 5, 6]

5.2 Repetition (*)

L = [0] * 5
print(L)

L2 = [1, 2] * 3
print(L2)

Output:

[0, 0, 0, 0, 0]
[1, 2, 1, 2, 1, 2]

5.3 Membership (in / not in)

L = [10, 20, 30, 40, 50]
print(30 in L) # True
print(35 in L) # False
print(100 not in L) # True

Output:

True
False
True

5.4 Comparison

print([1, 2, 3] == [1, 2, 3]) # True
print([1, 2, 3] == [3, 2, 1]) # False
print([1, 2] < [1, 3]) # True (compares element by element)

Output:

True
False
True

6. Traversing a List

6.1 Using for loop (direct)

L = [10, 20, 30, 40, 50]
for item in L:
 print(item, end=" ")

Output:

10 20 30 40 50

6.2 Using for loop with index

L = [10, 20, 30, 40, 50]
for i in range(len(L)):
 print(f"L[{i}] = {L[i]}")

Output:

L[0] = 10
L[1] = 20
L[2] = 30
L[3] = 40
L[4] = 50

7. Lists are MUTABLE

Unlike strings, you can change list elements in place.

L = [10, 20, 30, 40, 50]

# Change single element
L[0] = 99
print(L)

# Change a slice
L[1:3] = [200, 300]
print(L)

# Delete using del
del L[4]
print(L)

Output:

[99, 20, 30, 40, 50]
[99, 200, 300, 40, 50]
[99, 200, 300, 40]

Important, aliasing vs copying:

# Aliasing (both variables point to SAME list)
A = [1, 2, 3]
B = A # B is an alias, not a copy
B[0] = 99
print(A) # [99, 2, 3] -- A is also changed!

# Copying (independent copy)
A = [1, 2, 3]
B = A[:] # B is a copy (using slicing)
# or: B = list(A)
# or: B = A.copy
B[0] = 99
print(A) # [1, 2, 3] -- A is unchanged

Output:

[99, 2, 3]
[1, 2, 3]

8. Nested Lists

A list can contain other lists as elements.

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

# Access element: matrix[row][col]
print(matrix[0]) # [1, 2, 3] (first row)
print(matrix[1][2]) # 6 (row 1, col 2)
print(matrix[2][0]) # 7 (row 2, col 0)

# Traverse nested list
for row in matrix:
 for item in row:
 print(item, end=" ")
 print

Output:

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

9. List Methods

9.1 len, Number of elements

L = [10, 20, 30]
print(len(L))

Output:

3

9.2 list, Convert to list

print(list("ABC"))
print(list(range(5)))
print(list((1, 2, 3)))

Output:

['A', 'B', 'C']
[0, 1, 2, 3, 4]
[1, 2, 3]

9.3 append, Add element at end

Syntax: list.append(element)

L = [1, 2, 3]
L.append(4)
print(L)

L.append([5, 6]) # adds list as single element
print(L)

Output:

[1, 2, 3, 4]
[1, 2, 3, 4, [5, 6]]

9.4 extend, Add all elements of iterable

Syntax: list.extend(iterable)

L = [1, 2, 3]
L.extend([4, 5, 6])
print(L)

L.extend("AB")
print(L)

Output:

[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 'A', 'B']

Key difference: append adds the argument as a single element; extend adds each element of the argument individually.


9.5 insert, Insert element at specific position

Syntax: list.insert(index, element)

L = [10, 20, 40, 50]
L.insert(2, 30) # insert 30 at index 2
print(L)

L.insert(0, 5) # insert at beginning
print(L)

Output:

[10, 20, 30, 40, 50]
[5, 10, 20, 30, 40, 50]

9.6 count, Count occurrences of element

Syntax: list.count(element)

L = [1, 2, 3, 2, 4, 2, 5]
print(L.count(2))
print(L.count(9))

Output:

3
0

9.7 index, Find position of first occurrence

Syntax: list.index(element[, start[, end]])

L = [10, 20, 30, 20, 40]
print(L.index(20)) # 1 (first occurrence)
print(L.index(20, 2)) # 3 (search from index 2)
# print(L.index(99)) # ValueError: 99 is not in list

Output:

1
3

9.8 remove, Remove first occurrence of element

Syntax: list.remove(element)

L = [10, 20, 30, 20, 40]
L.remove(20) # removes first 20
print(L)
# L.remove(99) # ValueError: list.remove(x): x not in list

Output:

[10, 30, 20, 40]

9.9 pop, Remove and return element at index

Syntax: list.pop([index])

L = [10, 20, 30, 40, 50]

item = L.pop # removes and returns last element
print(item)
print(L)

item = L.pop(1) # removes and returns element at index 1
print(item)
print(L)

Output:

50
[10, 20, 30, 40]
20
[10, 30, 40]

Difference between del, remove, and pop:

del L[i] L.remove(val) L.pop(i)
Works by Index Value Index
Returns Nothing Nothing Removed element
If not found IndexError ValueError IndexError

9.10 reverse, Reverse list in place

Syntax: list.reverse

L = [1, 2, 3, 4, 5]
L.reverse
print(L)

Output:

[5, 4, 3, 2, 1]

9.11 sort, Sort list in place

Syntax: list.sort([key][, reverse])

L = [30, 10, 50, 20, 40]
L.sort
print(L)

L.sort(reverse=True)
print(L)

names = ["Charlie", "Alice", "Bob"]
names.sort
print(names)

Output:

[10, 20, 30, 40, 50]
[50, 40, 30, 20, 10]
['Alice', 'Bob', 'Charlie']

9.12 sorted, Return new sorted list (does not change original)

Syntax: sorted(iterable[, key][, reverse])

L = [30, 10, 50, 20, 40]
L2 = sorted(L)
print(L2)
print(L) # original unchanged

Output:

[10, 20, 30, 40, 50]
[30, 10, 50, 20, 40]

Key difference: sort modifies the original list and returns None; sorted returns a new list and keeps the original unchanged.


9.13 min, max, sum

L = [10, 20, 5, 40, 15]
print(min(L))
print(max(L))
print(sum(L))
print(sum(L) / len(L)) # mean/average

Output:

5
40
90
18.0

10. List vs String

Feature List String
Type list str
Mutable? Yes No
Elements Any type Characters only
Syntax [1, 2, 3] "abc"
Change element L[0] = 99 Not allowed
Methods append, extend, sort, etc. upper, lower, split, etc.
Common Indexing, slicing, in, +, *, len Same

11. List Comprehension

A concise way to create lists.

Syntax: [expression for item in iterable if condition]

# Squares of 1 to 5
squares = [x**2 for x in range(1, 6)]
print(squares)

# Even numbers from 1 to 20
evens = [x for x in range(1, 21) if x % 2 == 0]
print(evens)

# First letter of each word
words = ["Hello", "World", "Python"]
initials = [w[0] for w in words]
print(initials)

# Convert all to uppercase
names = ["alice", "bob", "charlie"]
upper_names = [n.upper for n in names]
print(upper_names)

Output:

[1, 4, 9, 16, 25]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
['H', 'W', 'P']
['ALICE', 'BOB', 'CHARLIE']

12. Practice Programs

Program 1: Find max, min, mean of list

L = eval(input("Enter a list: "))

print("Maximum:", max(L))
print("Minimum:", min(L))
print("Mean:", sum(L) / len(L))

Sample Run:

Enter a list: [10, 20, 30, 40, 50]
Maximum: 50
Minimum: 10
Mean: 30.0

Without built-in functions:

L = eval(input("Enter a list: "))

maximum = minimum = L[0]
total = 0

for item in L:
 if item > maximum:
 maximum = item
 if item < minimum:
 minimum = item
 total += item

print("Maximum:", maximum)
print("Minimum:", minimum)
print("Mean:", total / len(L))

Program 2: Linear search in list

L = eval(input("Enter a list: "))
item = int(input("Enter element to search: "))

found = False
for i in range(len(L)):
 if L[i] == item:
 print(f"Element {item} found at index {i}")
 found = True
 break

if not found:
 print(f"Element {item} not found in list")

Sample Run:

Enter a list: [10, 20, 30, 40, 50]
Enter element to search: 30
Element 30 found at index 2

Program 3: Count frequency of elements

L = eval(input("Enter a list: "))

checked = []
for item in L:
 if item not in checked:
 print(f"{item} appears {L.count(item)} time(s)")
 checked.append(item)

Sample Run:

Enter a list: [1, 2, 3, 2, 1, 3, 3]
1 appears 2 time(s)
2 appears 2 time(s)
3 appears 3 time(s)

Program 4: Remove duplicates

L = eval(input("Enter a list: "))

# Method 1: Using new list
result = []
for item in L:
 if item not in result:
 result.append(item)
print("Without duplicates:", result)

# Method 2: Using set (order may not be preserved in older Python)
# print(list(set(L)))

Sample Run:

Enter a list: [1, 2, 3, 2, 4, 1, 5]
Without duplicates: [1, 2, 3, 4, 5]

Program 5: Swap even and odd index elements

L = eval(input("Enter a list: "))
print("Original:", L)

for i in range(0, len(L) - 1, 2):
 L[i], L[i + 1] = L[i + 1], L[i]

print("After swap:", L)

Sample Run:

Enter a list: [1, 2, 3, 4, 5, 6]
Original: [1, 2, 3, 4, 5, 6]
After swap: [2, 1, 4, 3, 6, 5]

Program 6: Flatten nested list

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

for sublist in nested:
 for item in sublist:
 flat.append(item)

print("Nested:", nested)
print("Flat:", flat)

Output:

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

Using list comprehension:

nested = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
flat = [item for sublist in nested for item in sublist]
print("Flat:", flat)

Program 7: Sort list in ascending/descending

L = eval(input("Enter a list: "))

print("Ascending:", sorted(L))
print("Descending:", sorted(L, reverse=True))

Sample Run:

Enter a list: [30, 10, 50, 20, 40]
Ascending: [10, 20, 30, 40, 50]
Descending: [50, 40, 30, 20, 10]

Program 8: Merge two sorted lists

L1 = eval(input("Enter first sorted list: "))
L2 = eval(input("Enter second sorted list: "))

merged = []
i = j = 0

while i < len(L1) and j < len(L2):
 if L1[i] <= L2[j]:
 merged.append(L1[i])
 i += 1
 else:
 merged.append(L2[j])
 j += 1

# Add remaining elements
merged.extend(L1[i:])
merged.extend(L2[j:])

print("Merged:", merged)

Sample Run:

Enter first sorted list: [1, 3, 5, 7]
Enter second sorted list: [2, 4, 6, 8]
Merged: [1, 2, 3, 4, 5, 6, 7, 8]

Program 9: Second largest element

L = eval(input("Enter a list: "))

largest = second = float('-inf')

for item in L:
 if item > largest:
 second = largest
 largest = item
 elif item > second and item != largest:
 second = item

if second == float('-inf'):
 print("No second largest element")
else:
 print("Second largest:", second)

Sample Run:

Enter a list: [10, 20, 30, 40, 50]
Second largest: 40

Simpler approach:

L = eval(input("Enter a list: "))
unique = list(set(L))
unique.sort
print("Second largest:", unique[-2])

Program 10: Split list into even and odd numbers

L = eval(input("Enter a list: "))

even = []
odd = []

for item in L:
 if item % 2 == 0:
 even.append(item)
 else:
 odd.append(item)

print("Even numbers:", even)
print("Odd numbers:", odd)

Sample Run:

Enter a list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Even numbers: [2, 4, 6, 8, 10]
Odd numbers: [1, 3, 5, 7, 9]

Using list comprehension:

L = eval(input("Enter a list: "))
even = [x for x in L if x % 2 == 0]
odd = [x for x in L if x % 2 != 0]
print("Even:", even)
print("Odd:", odd)

13. Common Mistakes

Mistake Why it is wrong Correct way
L.append([4,5]) expecting [1,2,3,4,5] append adds as single element Use L.extend([4,5])
L2 = L expecting a copy Creates alias (same object) L2 = L[:] or L2 = L.copy
L.sort and using return value sort returns None Use sorted(L) if you need the return
L.remove(99) without checking Raises ValueError if not found Check if 99 in L: first
Modifying list while iterating Unexpected behavior / skipped items Iterate over a copy or use list comprehension
L.pop(99) with invalid index IndexError Check len(L) first

$1$2 Quick Tips

  1. Mutable vs Immutable is the most asked conceptual question. Know that lists are mutable (can be changed in place) unlike strings and tuples.

  2. Know the difference between append and extend, a very frequent exam question.

  3. Know the difference between sort and sorted, sort changes original, returns None; sorted returns new list.

  4. Aliasing trap: B = A does not create a copy. Both point to the same list. Use B = A[:] for a true copy. Exams love to test this.

  5. List comprehension is a favorite for 1-2 mark questions. Be comfortable reading and writing them.

  6. del, remove, pop, know when to use which. pop is the only one that returns the removed element.

  7. For output-prediction questions: Trace through the code step by step, keeping track of the list's state after each operation.

Test Your Knowledge

Take a quick quiz on this lesson

Start Quiz →

Prefer watching over reading?

Subscribe for free.

Subscribe on YouTube