Python for Beginners: Understanding Sequences with Lists and Tuples

python basic

What is a sequence?

Imagine a sequence as a row of labeled storage lockers, each representing a variable in the world of programming.
(If you’re familiar with other programming languages, you can think of a sequence as a way to organize and manage similar data in a convenient manner.)

In this analogy, each locker can hold only one item of data, similar to how a variable can store a single value.

However, the power of sequences lies in their ability to group multiple similar items together under a common umbrella. Just like lockers have unique numbers, sequences are structured with indices or positions to identify and access individual elements. This numbering system allows you to easily retrieve specific pieces of data, even if you momentarily forget where they are stored.

In essence, a sequence is a collection that enables you to manage various pieces of data collectively, giving them order through numerical indices. This fundamental concept is crucial for beginners in Python, providing a structured way to work with and organize information in their programs.

String

Strings, in Python, are a type of sequence, and the Python documentation officially categorizes them as “text sequence types.” This means that when you’re working with strings, you’re essentially working with a sequence of characters.

For instance, consider the following string:

word = "HelloWorld"

While it might seem like the variables contains the entire 10-character word “HelloWorld,” in reality, it’s more accurate to say that “variable word is a sequence of 10 elements, each of which contains the letters H, e, l, l, o, W, o, r, l, and d, in order from the beginning.

To illustrate this concept further, think of the string as a row of lockers, each locker containing one letter. The numbers above the characters represent the index starting from 0. This is because, in Python, indexing begins at 0, and in the case of our string, it goes up to 9 (for a total of 10 elements).

0123456789
HelloWorld
-10-9-8-7-6-5-4-3-2-1

Additionally, there are negative numbers listed below the lockers. These negative numbers allow you to trace backward from the end of the sequence. So, using -1 would refer to the last element, -2 to the second-to-last, and so on. This indexing approach offers flexibility when navigating through the elements of a string.

To understand strings as sequences and grasp the indexing system, both positive and negative, is crucial for Python beginners as it forms the foundation for manipulating and accessing individual elements within a string.

String Slicing

In Python, the concept of slicing is not limited to just strings; it can be applied to other sequences like lists as well.

Slicing involves extracting a portion of a sequence.

Let’s explore the slicing operation using a string as an example. Consider the string below, comprising 26 lowercase letters from ‘a’ to ‘z’:

a = "abcdefghijklmnopqrstuvwxyz"

Now, let’s delve into different ways of extracting elements from this sequence.

Obtaining one specific element

To retrieve a specific element, use the syntax

string_name[number].

Note that Python uses zero-based indexing.

print(a[0])
print(a[10])
print(a[25])

Output :

a
k
z

Also, let’s explore the use of negative numbers to reference elements from the end of the sequence.

print(a[-1])
print(a[-10])
print(a[-26])

Output:

z
q
a

Negative indices provide a convenient way to access elements from the end of the sequence.

Extracting a Partial String

To obtain a subset of characters from a string, use the syntax below :

string_name[start : end]

This allows you to retrieve the portion of the string from the start position up to, but not including, the end position. Pay attention to the end position to avoid off-by-one errors.

a[0:5]

Output:

abcde

You can omit both the start and end positions. When omitted, the start position defaults to 0, and the end position defaults to the length of the string.

print(a[:5])
print(a[5:])
print(a[:-15])
print(a[:])

Output:

abcde
fghijklmnopqrstuvwxyz
abcdefghijk
abcdefghijklmnopqrstuvwxyz

Moreover, you can retrieve strings with increments by adding a third colon (:) and specifying the increment value. The syntax is below :

string_name[start :end :nincrement]

print(a[0:10:2])
print(a[-1:-10:-2])

Output :

acegi
zxvtr

If the increment is a negative number, the retrieved string will be in reverse order.

Understanding these slicing techniques is essential for manipulating and extracting meaningful data from strings in Python.

List

Previously, we discussed strings as “lockers with only one character in each element”. Now, let’s introduce a more versatile type of locker called a list.

A list can store strings with two or more characters in each element, as well as discrete numbers.

Creating List with [ ] (square-braket)

Lists can be easily created by enclosing elements inside square brackets [ ].

a = [1,5,26]
b = ["a", "b", "c"]
c = []
d = [10, "car", 3, "train"]

You can create an empty list (as in c) or a mixed list of strings and numbers (as in d). However, it’s generally recommended to stick to a single data type in a list to avoid unexpected errors when processing the data later.

You can also use type() to confirm that the variable is indeed a list.

# Check type of list
type(b)

Output :

list

Creating List with list() function

Another way to create a list is by using the list() function. This method is particularly useful when converting other types of sequences, like strings or range(), into lists.

# Example list creation with list()
e = list("HelloWorld")
print(e)  

f = list(range(1, 11, 2))
print(f)  

g = list()
print(g)

Output :

['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd']
[1, 3, 5, 7, 9]
[]

Note that when using list() with a string, it creates a list where each character becomes an individual element. Additionally, an empty list can be created with list() by providing no elements.

Understanding these different ways to create lists is essential for Python beginners as lists are a fundamental and versatile data structure in Python.

Referencing Elements of a List

When you want to refer elements in a list, you can use the “slice” notation introduced in the string section. Here are the different ways to reference elements:

  • List[number]
  • List[Start : End]
  • List[Start : End : Increment]

Let’s explore this using the lists a through g created in the previous chapter.

print(f[1])
print(f[1:3])
print(e[1:8:2])

Output :

3
[3, 5]
['e', 'l', 'W', 'r']

Creating a List with Comprehensive Notation

Another way to create a list, although a bit more advanced, is using list comprehension.

List Comprehensive Notation

We’ve shown how to create a list using list(range(1, 11, 2)). A similar method can be achieved using [ ] brackets.

h = [i for i in range(1, 11, 2)]
print(h)

The i for i in range(1, 11, 2) may seem confusing initially. Let’s break it down.

If we exclude the initial “i,” the code for i in range(1, 11, 2) can be understood as follows:
It instructs Python to pick consecutive odd numbers, starting from 1 and going up to 10 (not include 11), with an increment of 2. Each of these odd numbers is then stored in the variable ‘i’ for further processing.

Output :

[1, 3, 5, 7, 9]

Now, let’s consider another example:

add_10 = [(i + 10) for i in range(1, 11, 2)]
print(add_10)
  • List Comprehension: [(i + 10) for i in range(1, 11, 2)] is a compact way of creating a list. For each number in the range (1, 11, 2), it adds 10 to that number and collects the results into a new list.
  • range(1, 11, 2): This part produces the numbers 1, 3, 5, 7, and 9.
  • (i + 10): This part represents adding 10 to each number generated by the range. For example, if the current number is 1, then 1 + 10 is 11. If the current number is 3, then 3 + 10 is 13, and so on.
  • Resulting List ‘add_10’: The final result is a list named add_10 containing the numbers obtained by adding 10 to each of the numbers in the specified range. So, add_10 will be the list [11, 13, 15, 17, 19].

Output :

[11, 13, 15, 17, 19]

This method is called list comprehension, and it allows for data processing while creating a new list from a sequence.

Using “if” in Comprehensive Notation:

Comprehensive expressions in Python also support the use of the if statement, allowing you to filter and store only data that satisfies specific conditions in a new list.

In this case, the if conditional expression is placed after the for statement without the need for a colon.

a = [i for i in range(11) if i % 2 == 1]
print(a)
  1. for i in range(11): This is a loop that iterates over each element (i) in the range from 0 to 10.
  2. if i % 2 == 1: This is a condition that checks whether the current value of i is odd. The % operator is the modulus operator, and i % 2 calculates the remainder when i is divided by 2. If the remainder is 1, it means i is an odd number.
  3. [i for i in range(11) if i % 2 == 1]: This is a list comprehension. It creates a new list by including only those values of i from the range (0 to 10) that satisfy the condition i % 2 == 1 (i.e., odd numbers).
    • When i is 1, 3, 5, 7, and 9, the condition i % 2 == 1 is True, so those values are included in the list.
    • When i is 0, 2, 4, 6, 8, and 10, the condition is False, so those values are excluded from the list.

Output :

[1, 3, 5, 7, 9]

Logical operators can also be used in comprehension notation to apply multiple conditions:

b = [i for i in range(11) if i % 2 == 1 and i % 3 == 0]
print(b)

Output :

[3, 9]

Using “if-else” in Comprehensive Notation:

Comprehensive notation doesn’t stop at just if; you can also incorporate if ... else .... If you want to use else along with if, you should place it before the for statement.

b = ["even" if i % 2 == 0 else "odd" for i in range(11)]
print(b)

Output :

['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even']

Here, the string “even” is added to the list when the condition i % 2 == 0 is satisfied, and the string “odd” is added when it is not satisfied.

It’s important to note that elif cannot be used directly in comprehensions. If you need to handle more than two conditions, you can use an if in the else clause. However, in this case, you can use a workaround by putting another if inside the else clause. This allows the code to handle more than two conditions.

c = ["Try Harder" if i < 60 else "OK" if i < 90 else "Good Job" for i in range(0, 101, 10)]
print(c)

Output :

['Try Harder', 'Try Harder', 'Try Harder', 'Try Harder', 'Try Harder', 'Try Harder', 'OK', 'OK', 'OK', 'Good Job', 'Good Job']
  1. range(0, 101, 10) generates a sequence of numbers starting from 0 up to (but not including) 101 with a step size of 10, resulting in the list [0, 10, 20, 30, ..., 90, 100].
  2. The list comprehension iterates through each value i in the generated sequence.
  3. The code checks three conditions in order for each value of i:
  • If i is less than 60, the element in the list is “Try Harder”.
  • If the first condition is not met and i is less than 90, the element becomes “OK”.
  • If neither of the above conditions is met, the element is “Good Job”.

In summary, the code generates a list of strings based on certain conditions for each value in the range [0, 100] with a step size of 10. It uses an if statement inside the else clause to handle multiple conditions when assigning strings to the list elements.

How to Manage List

In Python, lists provide the flexibility to add, remove, and manipulate elements dynamically. This section explains the basic operations for managing the information in a list, following the CRUD acronym: “Create,” “Read,” “Update,” and “Delete.”

Adding a New Element

To add an element to the end of a list, you can use the append() method, which is one of the built-in methods for lists.

months = ["January", "March"]
print(months)

months.append("April")
print(months)

Output :

['January', 'March']
['January', 'March', 'April']

The append() method adds an element to the tail of the list.

If you want to insert an element at a specific position other than the end, you can use the insert() method.

insert(insert_position, element)

months.insert(1, "February")
print(months)

Output :

['January', 'February', 'March', 'April']

Concatenating Another Listing

Lists can be combined by concatenating them, forming a new list. The + operators are used for concatenation.

a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
print(c)

d = c + [7, 8, 9]
print(d)

Output :

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

Additionally, the * operators can be used to repeatedly concatenate a specific list into a new list.

e = a * 3
print(e)

Output :

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

Understanding these operations is crucial for efficiently managing and manipulating data within lists in Python. The provided examples illustrate how to add elements and concatenate lists, showcasing the dynamic nature of Python lists.

Element Reference

To reference an element in a list, you can use the “slice” notation as mentioned earlier. Let’s continue exploring this with the example of months.

print(months[1])
print(months[3])

Output :

February
April

Unpacking

For storing each element in a list into separate variables, you can use the “unpacking” method.

months = ['January', 'February', 'March', 'April']
a, b, c, d = months
print(a)
print(b)
print(c)
print(d)

Output :

January
February
March
April

Here, the list elements are assigned to variables a, b, c and d in the order they are listed.

Updating Elements

To change the contents of a particular element, you can use “slice” to overwrite the data; there is no dedicated method.

months[0] = "JAN"
print(months)

Output :

['JAN', 'February', 'March', 'April']

Note that attempting to update an element at a non-existent index will result in an error.

To avoid this, use append() to add elements to the end of the list.

Deleting Elements

To remove a specific element from a list, use the pop() method. If no argument is provided, it removes the last element.

months = ['January', 'February', 'March', 'April']

months.pop()
print(months)

months.pop()
print(months)

Output :

['January', 'February', 'March']
['January', 'February']

The pop() method returns the elements removed from the list.

Numeric values can be specified in pop() to delete an element at a specific location. Negative numbers can also be used to specify positions in reverse order. To clear all elements in the list, use the clear() method.

months = ['January', 'February', 'March', 'April']

# Deleting an element at a specific location using pop()
months_poped = months.pop(1)
print(months_poped)

months_reverse = months.pop(-1)
print(months_reverse)

# Clearing all elements in the list using clear()
months.clear()
print(months)

Output :

February
April
[]

In this example, we have a list months containing the names of different months. The code demonstrates how to use the pop() method to remove a month at a specific position (both forward and in reverse order) and how to use the clear() method to remove all months from the list.

Searching for Elements

There are also methods to check if a specified element exists in the list.

The count() method returns the number of specified elements in the list.

words = list("HelloWorld")
print(words.count("H"))
print(words.count("o"))
print(words.count("b"))

Output :

1
2
0

The index() method returns the position of the specified element. If the element is not found, it raises a ValueError.

words = list("HelloWorld")
print(words.index("H"))
print(words.index("o"))

Output :

0
4

The in keyword can be used to check if a specified element is present in the list.

"o" in words

Output :

True

This is effective when combined with an if statement. Python lists offer various other useful methods.

words = ["apple", "banana", "orange", "grape"]

if "orange" in words:
    print("The orange is present in the list.")
else:
    print("The orange is not present in the list.")

Output :

The orange is present in the list.

Reordering Elements

If you wish to reorder elements in a list, Python provides convenient methods to achieve this. .

Sorting Numeric Lists:

For a list of numbers, you can use the sort() method to sort elements in ascending order (from smallest to largest).

num_lists = [3, 1, 4, 5, 2]

num_lists.sort()
print(num_lists)

Output :

[1, 2, 3, 4, 5]

The reverse() method can then be applied to reverse the order.

num_lists = [3, 1, 4, 5, 2]

num_lists.reverse()
print(num_lists)

Output :

[2, 5, 4, 1, 3]

In order to reverse the order from largest to smallest

num_lists = [3, 1, 4, 5, 2]

num_lists.sort()
print(num_lists)

num_lists.reverse()
print(num_lists)

Output :

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

Note that both sort() and reverse() are destructive methods, meaning they modify the original list without reassignment.

Sorting String Lists:

For a list of strings, the sort() method arranges elements in alphabetical order, while reverse() reverses the order.

friends = ["Tom", "John", "Carry", "Steve", "Nancy"]

friends.sort()
print(friends)

friends.reverse()
print(friends)

Output :

['Carry', 'John', 'Nancy', 'Steve', 'Tom']
['Tom', 'Steve', 'Nancy', 'John', 'Carry']

Note that both sort() and reverse() are destructive methods, meaning they modify the original list without reassignment.

Non-Destructive Sorting:

To sort a list non-destructively, use the built-in sorted() function. This function returns a new sorted list, leaving the original list unchanged. You can use the reverse argument to control the sorting order.

num_lists = [3, 1, 4, 5, 2]
sorted_lists = sorted(num_lists)
reversed_lists = sorted(num_lists, reverse=True)

print(num_lists)
print(sorted_lists)
print(reversed_lists)

Output :

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

Understanding these methods allows you to easily manipulate the order of elements within your lists, catering to various sorting needs in Python.

Iteration and Lists

Using lists and iteration together allows you to dynamically build and process data.

cities = []

# Register cities to the list
while True:
    city = input("Enter a city name (press Enter to stop): ")

    if city == "":
        break

    cities.append(city)

# Display cities
print("Cities you entered:")
for i in range(len(cities)):
    print(cities[i])

print("DONE")

Example Output:

Enter a city name (press Enter to stop): Chicago
Enter a city name (press Enter to stop): Seattle
Enter a city name (press Enter to stop): New York
Enter a city name (press Enter to stop): San Francisco
Enter a city name (press Enter to stop): 
Cities you entered:
Chicago
Seattle
New York
San Francisco
DONE

In this example, the program uses an infinite loop to continuously receive city names until the user presses Enter without entering a name. The append() method adds each city name to the list, and the for loop iterates through the list, printing each element.

Two-dimensional Lists

Two-dimensional lists are like tables, allowing you to access elements using both vertical and horizontal indices. You can create and access two-dimensional lists as follows:

123
456
789
twoD_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

print(twoD_lists[0][2])
print(twoD_lists[2][1])

Output:

3
8

The followin program creates a 2D list.

rows = 3
cols = 3

# Method 1: Using nested loops
matrix1 = []
for i in range(rows):
    row = []
    for j in range(cols):
        row.append(i * cols + j + 1)
    matrix1.append(row)

print(matrix1)

Output :

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

List comprehension can also be used to create two-dimensional lists:

rows = 3
cols = 3

# Method 2: Using list comprehension
matrix2 = [[i * cols + j + 1 for j in range(cols)] for i in range(rows)]

print(matrix2)

Output :

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

Understanding iteration and two-dimensional lists broadens your ability to manipulate data in Python.

zip()

The zip() function is a powerful tool to combine multiple lists into one.

# Sample lists
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 22]
scores = [95, 87, 92]

# Using zip() to combine lists
combined_data = zip(names, ages, scores)

# Converting the result to a list (as zip() returns an iterator)
combined_list = list(combined_data)

# Accessing elements in the combined list
for item in combined_list:
    print("Name:", item[0], "| Age:", item[1], "| Score:", item[2])

Output :

Name: Alice | Age: 25 | Score: 95
Name: Bob | Age: 30 | Score: 87
Name: Charlie | Age: 22 | Score: 92

Two points to note: each element in the new list is a tuple, and the resulting list consists of tuples aligned vertically.

Difference between a Tuple and a List

In Python, a tuple is a collection of ordered and immutable elements, which means once you create a tuple, you cannot change its contents.

Tuples are defined by enclosing elements in parentheses, and they can store different data types, including numbers, strings, and even other tuples.

Unlike lists, tuples provide a fixed structure, making them useful for storing related pieces of information that should remain constant throughout your program. You can access individual elements in a tuple using indexing, and tuples are commonly used to group related data together in a way that maintains a consistent and unchangeable sequence.

Tuples and lists are both structures that can hold multiple elements, but the key distinction lies in mutability. Lists are mutable, meaning elements can be modified after creation, while tuples are immutable, preventing any modifications, additions, or deletions once created.

The existence of tuples in Python serves three primary purposes:

  1. Performance: Tuples are generally faster than lists because they have fewer built-in functions. While this speed advantage may not be as noticeable on modern computers, it remains a consideration.
  2. Constants: Tuples are suitable for storing constant values. Similar to using variables for clarity in understanding, tuples help manage multiple data elements without intending to change them.
  3. Dictionary Keys: Tuples can be used as keys in dictionaries (covered in the dictionary lesson). For now, understand that tuples have special use cases with dictionaries.”

Creating Tuples

Tuples are created using parentheses ()

fruits_tuple = ('apple', 'banana', 'orange', 'grape')
print(fruits_tuple)

Output :

('apple', 'banana', 'orange', 'grape')

Unlike lists, new elements cannot be added to a tuple.

However, the variable storing the tuple can be reassigned:

fruits_tuple = ("green_apple", "peach", "melon", "strawberry")
print(fruits_tuple)

Output :

('green_apple', 'peach', 'melon', 'strawberry')

The + and * operators are nondestructive for tuples, allowing concatenation and repetition without modifying the original tuples:

a = (1, 2, 3)
b = (4, 5, 6)
c = a + b
print(c)

Output :

(1, 2, 3, 4, 5, 6)

Understanding tuples enhances your ability to design efficient and purposeful data structures in Python.

Creating Tuples with tuple()

The tuple() function is a versatile tool for creating tuples from various sequences.

a = tuple("HelloWorld")

print(a)

Output :

('H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd')

Using Tuples

Tuples have distinct characteristics compared to lists; they cannot register, update, or delete new elements. However, referencing and searching for elements remain possible.

Referencing Elements

Similar to lists, slices are used for referencing elements within tuples.

a = tuple("HelloWorld")
print(a[2:5])

Output :

('l', 'l', 'o')

Unpacking is also feasible with tuples.

months = ('January', 'February', 'March', 'April')
a, b, c, d = months
print(a)
print(b)
print(c)
print(d)

Output :

January
February
March
April

Retrieving Elements

Tuples offer count() and index() functions for element retrieval.

a = tuple("HelloWorld")
print(a.count("l"))
print(a.index("W"))
print("e" in a)

Output :

3
5
True

Summary

Congratulations on completing this lesson! Let’s summarize what you’ve learned about sequences, lists, and tuples, and discuss some next steps.

Sequences Recap:

  • Sequences are ordered collections of elements.
  • Python supports various sequence types, including strings, lists, and tuples.
  • Elements in a sequence are accessible through indexing.
  • Slices provide a way to extract multiple elements from a sequence.

Lists in Python:

  • Lists are versatile and mutable sequences.
  • You can modify, add, and remove elements from a list.
  • Methods like append(), insert(), pop(), sort(), and reverse() offer powerful list manipulation.

Tuples in Python:

  • Tuples are immutable sequences, meaning their elements cannot be changed after creation.
  • They are created using parentheses, and a single-element tuple requires a trailing comma.
  • Tuples offer benefits like faster processing and are suitable for constant values.