Week 6: Mastering Lists - Your First Data Structure

Learn how to organize and manipulate data using lists in Python.

Explore Chapter 6

Chapter 6: Organizing Data with Lists

Introduction to Lists: Creating, Accessing Elements.

Lists are one of the most versatile and commonly used data structures in Python. A list is an ordered collection of items. This means that each item in a list has a specific position, known as its index.

Creating Lists

You can create a list by enclosing a comma-separated sequence of items in square brackets `[]`. Lists can contain items of different data types (though often, you'll work with lists of the same type).

# Empty list
my_list = []

# List of integers
numbers = [1, 2, 3, 4, 5]

# List of strings
colors = ["red", "green", "blue"]

# List of mixed data types
mixed_list = [1, "hello", 3.14, True]

Accessing Elements

You access elements in a list using their index. List indices start at 0 for the first element, 1 for the second, and so on.

fruits = ["apple", "banana", "cherry"]
first_fruit = fruits[0]  # "apple"
second_fruit = fruits[1] # "banana"
third_fruit = fruits[2]  # "cherry"

# Negative indexing
last_fruit = fruits[-1]   # "cherry" (last element)
second_last = fruits[-2]  # "banana"

Attempting to access an index that is out of range will raise an `IndexError`.

List Indexing: Getting Specific Items.

As seen in the introduction, list indexing allows you to retrieve individual elements from a list. It's crucial for accessing and manipulating data within lists.

Basic Indexing

Use square brackets `[]` with the index inside to access the corresponding element.

my_list = [10, 20, 30, 40, 50]
print(my_list[0])  # Output: 10 (first element)
print(my_list[3])  # Output: 40 (fourth element)

Negative Indexing

Negative indices allow you to access elements from the end of the list. `-1` refers to the last element, `-2` to the second-to-last, and so on.

my_list = [10, 20, 30, 40, 50]
print(my_list[-1]) # Output: 50 (last element)
print(my_list[-3]) # Output: 30

List Slicing: Extracting Sublists.

Slicing is a powerful technique for creating new lists that are sub-sequences of an existing list. The syntax for slicing is `[start:stop:step]`.

  • `start`: The index where the slice starts (inclusive). If omitted, defaults to 0.
  • `stop`: The index where the slice ends (exclusive). If omitted, defaults to the end of the list.
  • `step`: The step (or stride) between elements in the slice. If omitted, defaults to 1.
my_list = [10, 20, 30, 40, 50, 60, 70, 80]

print(my_list[1:4])    # Output: [20, 30, 40] (elements from index 1 up to, but not including, 4)
print(my_list[:3])     # Output: [10, 20, 30] (elements from the beginning up to index 3)
print(my_list[4:])     # Output: [50, 60, 70, 80] (elements from index 4 to the end)
print(my_list[:])      # Output: [10, 20, 30, 40, 50, 60, 70, 80] (a copy of the entire list)
print(my_list[1:7:2])  # Output: [20, 40, 60] (elements from 1 to 7 with a step of 2)
print(my_list[::-1])   # Output: [80, 70, 60, 50, 40, 30, 20, 10] (reversing the list)

Common List Methods: Modifying and Manipulating Lists.

Lists in Python come with a set of built-in methods that allow you to modify, add, remove, and manipulate list elements.

  • `append(element)`: Adds an `element` to the end of the list.
    fruits = ["apple", "banana"]
    fruits.append("orange") # fruits is now ["apple", "banana", "orange"]
  • `insert(index, element)`: Inserts an `element` at a specific `index` in the list.
    fruits = ["apple", "banana"]
    fruits.insert(1, "mango") # fruits is now ["apple", "mango", "banana"]
  • `remove(element)`: Removes the first occurrence of the `element` from the list. Raises a `ValueError` if the element is not found.
    fruits = ["apple", "banana", "cherry"]
    fruits.remove("banana") # fruits is now ["apple", "cherry"]
  • `pop(index)`: Removes and returns the element at the specified `index`. If no `index` is provided, it removes and returns the last element.
    fruits = ["apple", "banana", "cherry"]
    removed_fruit = fruits.pop(1) # removed_fruit is "banana", fruits is now ["apple", "cherry"]
    last_fruit = fruits.pop()    # removes and returns "cherry"
  • `sort()`: Sorts the list in ascending order (in place, meaning it modifies the original list). You can use `sort(reverse=True)` to sort in descending order.
    numbers = [3, 1, 4, 1, 5, 9, 2, 6]
    numbers.sort()        # numbers is now [1, 1, 2, 3, 4, 5, 6, 9]
    numbers.sort(reverse=True) # numbers is now [9, 6, 5, 4, 3, 2, 1, 1]
    
    words = ["banana", "apple", "cherry"]
    words.sort()          # words is now ["apple", "banana", "cherry"]
  • `index(element)`: Returns the index of the first occurrence of the `element` in the list. Raises a `ValueError` if the element is not found.
    fruits = ["apple", "banana", "cherry"]
    banana_index = fruits.index("banana") # banana_index is 1
  • `count(element)`: Returns the number of times the `element` appears in the list.
    numbers = [1, 1, 2, 3, 1]
    count_of_ones = numbers.count(1) # count_of_ones is 3
  • `copy()`: Returns a shallow copy of the list. This creates a new list with the same elements, but it's a different list object in memory.
    original_list = [1, 2, 3]
    copied_list = original_list.copy() # copied_list is a new list [1, 2, 3]
  • And many more!

List Comprehension (Introduction): Concise List Creation.

List comprehension provides a concise way to create new lists based on existing iterables (like lists, tuples, ranges, etc.). It's a powerful feature in Python that can make your code more readable and efficient.

Basic Syntax

new_list = [expression for item in iterable if condition]
  • `expression`: The value to include in the new list.
  • `item`: The variable that takes on the value of each element in the `iterable`.
  • `iterable`: The sequence you want to iterate over.
  • `condition` (optional): A filter to include only certain items.

Examples

# Create a list of squares of numbers from 0 to 9
squares = [x ** 2 for x in range(10)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# Create a list of even numbers from 0 to 19
even_numbers = [x for x in range(20) if x % 2 == 0] # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# Create a list of uppercase versions of strings
words = ["hello", "world"]
upper_words = [word.upper() for word in words] # ["HELLO", "WORLD"]

List comprehensions can often replace `for` loops and make your code more compact, but it's important to use them judiciously to maintain readability.

Syllabus