beginnerPython Framework • Core Concepts

Lists: Working with Collections

Join 1.2k+ learners

Introduction to Lists

A list is a mutable, ordered sequence that can hold any type of data. Unlike variables that store single values, lists group multiple items under one name. They're defined with square brackets [] and items separated by commas. Lists are the workhorse of Python—used everywhere from simple todo apps to complex data processing.

Python
# Creating lists fruits = ["apple", "banana", "cherry"] mixed = [1, "Hello", 3.14, True] # Mixed types OK! empty = [] # Empty list print(len(fruits)) # 3 - number of items

Indexing: Accessing Elements

Every item has a position (index) starting from 0. Use square brackets to access elements. Python also supports negative indexing: -1 is the last item, -2 is second-to-last, and so on. This makes it easy to access elements from either end.

Python
nums = [10, 20, 30, 40, 50] # Positive indexing (from start) print(nums[0]) # 10 (first) print(nums[2]) # 30 (third) # Negative indexing (from end) print(nums[-1]) # 50 (last) print(nums[-2]) # 40 (second-to-last)

Basic Operations: Append & Extend

append() adds a single item to the end. extend() adds multiple items from another iterable. Both modify the list in-place. Use + to concatenate and create a new list instead.

Python
cart = ["milk", "bread"] # append() - add ONE item cart.append("eggs") print(cart) # ['milk', 'bread', 'eggs'] # extend() - add MULTIPLE items cart.extend(["butter", "cheese"]) print(cart) # ['milk', 'bread', 'eggs', 'butter', 'cheese'] # Difference: append adds list AS item cart.append(["jam"]) # Adds ["jam"] as single element!

Insert: Adding at Specific Position

insert(index, item) adds an element at any position. All items after that index shift right. This is slower than append() because it requires moving elements.

Python
tasks = ["wake up", "work", "sleep"] # Insert at index 1 tasks.insert(1, "breakfast") print(tasks) # ['wake up', 'breakfast', 'work', 'sleep'] # Insert at beginning tasks.insert(0, "alarm") # Insert at end (same as append) tasks.insert(len(tasks), "dream")

Remove, Pop & Clear

remove(value) deletes the first occurrence of a value. pop(index) removes and returns an item (default: last). clear() empties the entire list. Use del for removing by index without returning.

Python
items = ["a", "b", "c", "b", "d"] # remove() - by VALUE (first match) items.remove("b") print(items) # ['a', 'c', 'b', 'd'] # pop() - by INDEX, returns removed item last = items.pop() # 'd' (default: last) first = items.pop(0) # 'a' (specific index) # clear() - remove ALL items.clear() print(items) # []

Searching & Membership

Use 'in' for fast membership testing. index(value) returns the position of first occurrence (raises error if not found). count(value) tells how many times an item appears.

Python
grades = [85, 90, 78, 90, 92, 90] # Membership test - O(n) if 90 in grades: print("Found 90!") # Find position - O(n) pos = grades.index(90) # 1 (first occurrence) # Count occurrences - O(n) count = grades.count(90) # 3 # Safe search (avoid error) if 100 in grades: idx = grades.index(100)

Updating Elements

Lists are mutable—you can change any element by assigning to its index. You can also replace a range of elements using slice assignment.

Python
scores = [70, 80, 90, 85] # Update single element scores[0] = 75 print(scores) # [75, 80, 90, 85] # Update multiple via slicing scores[1:3] = [82, 95] print(scores) # [75, 82, 95, 85] # Replace with different length! scores[1:3] = [100] print(scores) # [75, 100, 85]

Slicing Basics

Slicing extracts a portion of a list using [start:end]. Start is inclusive, end is exclusive. Omit start to begin at 0, omit end to go to the end. Slicing creates a NEW list (shallow copy).

Python
nums = [0, 1, 2, 3, 4, 5, 6, 7] print(nums[2:5]) # [2, 3, 4] - index 2 to 4 print(nums[:3]) # [0, 1, 2] - first 3 print(nums[5:]) # [5, 6, 7] - from index 5 print(nums[:]) # Full copy # Negative indices work too! print(nums[-3:]) # [5, 6, 7] - last 3 print(nums[:-2]) # [0,1,2,3,4,5] - all but last 2

Advanced Slicing: Step Values

Add a third parameter [start:end:step] to skip elements. A step of 2 takes every other item. Negative step reverses direction—[::-1] is the classic way to reverse a list!

Python
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # Every 2nd element print(nums[::2]) # [0, 2, 4, 6, 8] # Every 3rd, starting at index 1 print(nums[1::3]) # [1, 4, 7] # REVERSE the list! print(nums[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] # Reverse portion print(nums[5:1:-1]) # [5, 4, 3, 2]

Copying & Cloning Lists

Assignment (=) creates a reference, not a copy! Both variables point to the SAME list. Use slicing [:], list(), or copy() for a shallow copy. For nested lists, use deepcopy() to clone everything.

Python
import copy original = [1, 2, [3, 4]] # WRONG - both point to same list! ref = original ref[0] = 99 print(original) # [99, 2, [3, 4]] - Changed! # Shallow copy - new outer list shallow = original[:] shallow[0] = 1 # Doesn't affect original shallow[2][0] = 33 # DOES affect original! # Deep copy - fully independent deep = copy.deepcopy(original) deep[2][0] = 333 # original unchanged

Sorting & Reversing

sort() modifies the list in-place (returns None). sorted() returns a NEW sorted list. Both accept key= for custom sorting and reverse=True for descending order. reverse() flips the list in-place.

Python
nums = [3, 1, 4, 1, 5, 9, 2, 6] # In-place sort - O(n log n) nums.sort() print(nums) # [1, 1, 2, 3, 4, 5, 6, 9] # Descending order nums.sort(reverse=True) # sorted() returns NEW list original = [3, 1, 2] new_sorted = sorted(original) print(original) # [3, 1, 2] - unchanged! # Custom key (sort by length) words = ["python", "is", "awesome"] words.sort(key=len) # ['is', 'python', 'awesome']

Nested Lists & 2D Grids

Lists can contain other lists, creating matrices or grids. Access elements with chained indices: grid[row][col]. Useful for tables, game boards, images, and spreadsheet-like data.

Python
# 3x3 grid matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # Access element at row 1, col 2 print(matrix[1][2]) # 6 # Modify element matrix[0][0] = 99 # Iterate over 2D list for row in matrix: for cell in row: print(cell, end=' ') print()

Nested Slicing

Combine indexing and slicing to extract portions of 2D lists. First index selects rows, then slice the inner list for columns. This is powerful for matrix operations.

Python
matrix = [ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12] ] # Get row 1 print(matrix[1]) # [5, 6, 7, 8] # Get element at [1][2] print(matrix[1][2]) # 7 # Slice columns from row 1 print(matrix[1][1:3]) # [6, 7] # Get column (need loop) col_1 = [row[1] for row in matrix] print(col_1) # [2, 6, 10]

Real-World: Shopping Cart

Lists are perfect for managing collections of items. Here's how you might implement a simple shopping cart with add, remove, and total calculations.

Python
cart = [] prices = {"apple": 1.5, "bread": 2.0, "milk": 3.0} # Add items cart.append("apple") cart.append("bread") cart.append("milk") cart.append("apple") # Can have duplicates # Remove item if "bread" in cart: cart.remove("bread") # Calculate total total = sum(prices[item] for item in cart) print(f"Cart: {cart}") print(f"Total: ${total:.2f}") # $6.00

Real-World: Grade Management

Process student grades with list operations. Calculate averages, find highest/lowest scores, and filter results—common data processing patterns.

Python
grades = [85, 92, 78, 90, 88, 76, 95, 89] # Statistics average = sum(grades) / len(grades) highest = max(grades) lowest = min(grades) # Filter passing grades (>= 80) passing = [g for g in grades if g >= 80] # Count A grades (>= 90) a_count = len([g for g in grades if g >= 90]) print(f"Avg: {average:.1f}") # 86.6 print(f"Highest: {highest}") # 95 print(f"Passing: {len(passing)}") # 6 print(f"A grades: {a_count}") # 3

Performance & Best Practices

Know your complexities: index access O(1), append O(1), insert/remove O(n), search O(n). Use deque for frequent insert/remove at both ends. Avoid modifying lists while iterating—use a copy or comprehension instead.

Python
# Time Complexity Cheat Sheet: # list[i] → O(1) constant # list.append → O(1) constant # list.pop() → O(1) from end # list.pop(0) → O(n) shifts all! # list.insert → O(n) shifts right # list.remove → O(n) search + shift # x in list → O(n) linear scan # list.sort → O(n log n) # For frequent ops at both ends: from collections import deque dq = deque([1, 2, 3]) dq.appendleft(0) # O(1) at front!

Master this concept

Hands-on practice is the fastest way to learn. Head over to our interactive workspace to solve this topic's challenge.

Launch Editor