Nested loops and working with two-dimensional arrays
Loops within a loop, or nested loops, are a fundamental tool in programming. They allow you not only to iterate over multidimensional data structures such as tables or matrices, but also to solve a wide range of tasks where multiple repetitions of the same action are required within another repetitive process. Imagine going through all the apartments in a multi-storey building: first you select a floor (outer loop), and then go through all the apartments on that floor (inner loop).
Nested loops work according to a simple and logical principle: the outer loop performs one of its iterations, after which control is transferred to the inner loop, which must perform all its iterations from beginning to end. Only after the inner loop is fully completed can the outer loop move on to its next iteration, and the process repeats.
Basic principles of nested loops:
- Starting the outer loop: The outer loop starts and executes its first iteration.
- Full run of the inner loop: The inner loop is activated and performs its full set of iterations.
- Next iteration of the outer loop: The outer loop proceeds to its next iteration, after which the inner loop starts again and performs its full set of iterations.
- Repetition: This process repeats until the outer loop completes all its iterations.
A useful tip: A great analogy for understanding nested loops is a clock. The outer loop is the hour hand, and the inner one is the minute hand. In one hour (one iteration of the outer cycle), the minute hand (the inner cycle) manages to make a complete revolution (all its iterations).
Example of nested loops
Consider a classic example: iterating through all the elements in a two-dimensional array (a list of lists).
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Outer loop by rows (by indexes)
for i in range(len(matrix)):
# Inner loop by row elements(by indexes)
for j in range(len(matrix[i])):
print(matrix[i][j], end=' ')
print() # Jump to a new line after output all elements of the current row
Step-by-step analysis:
- Initializing the outer loop: The
i variable (row index) starts at 0. The outer cycle enters its body.
- Initializing the inner loop: The variable
j (column index) starts at 0. The inner loop performs a full set of iterations for the first row (matrix[0]), iterating over all its elements.
- Output of the elements of the first line: The inner loop sequentially outputs
1, 2, 3.
- Completion of the inner loop: When the inner loop has finished working with the
matrix[0] string, control returns to the outer loop.
- The next iteration of the outer loop:
i becomes 1. The outer loop starts the inner loop again, which will now work with the second row (matrix[1]).
- Output of the elements of the second line: The inner loop outputs
4, 5, 6.
- This process is repeated for all rows of the matrix.
Style advice: Although index iteration (range(len(...))) is absolutely correct and often necessary, Python has a more readable and "Pythonic" way of iterating over elements.:
for row in matrix: # The outer loop takes each row directly
for element in row: # The inner loop takes each element from the current row
print(element, end=' ')
print()
This approach reduces the amount of code, makes it more expressive, and reduces the risk of index-related errors.
Two-dimensional arrays
Python does not have a built-in "two-dimensional array" type, as in some other languages. Instead, an extremely flexible structure is used - a list of lists, where each nested list is a row (or row) of an array. Let's look at different ways to create and fill them.
1. Manual input
The easiest way, ideal for small examples, tests and debugging.
# Example of a two-dimensional 3x3 array
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
2. Entering an array through loops
The classic and most fundamental way that needs to be well understood. It gives you full control over the process.
# Entering array sizes
rows = int(input("Enter the number of rows: "))
cols = int(input("Enter the number of columns: "))
matrix = [] # Creating an empty list for the entire matrix
for i in range(rows):
row = [] # Creating an empty list for the current row
for j in range(cols):
# Requesting each element
value = int(input(f"Enter the element [{i}][{j}]: "))
row.append(value)
matrix.append(row) # Adding the filled row to the matrix
3. Entering an array using list comprehension (list inclusions)
This is a more compact and advanced way, which is very much loved by experienced Python developers. It allows you to create a complex structure in one line.
rows = 3
cols = 3
# All the magic in one line
matrix = [[int(input(f"Element [{i}][{j}]: ")) for j in range(cols)] for i in range(rows)]
The Council: Although inclusion lists are very powerful, they should not be overused. If the logic gets too complicated, it's better to return to the usual for loops for the sake of code readability.
4. Entering a single-string array
A very common scenario in Olympiad programming or when reading data from a file is when all the numbers are given in one line separated by a space.
# Input string with numbers
input_string = "1 2 3 4 5 6 7 8 9"
rows, cols = 3, 3 # We know the sizes in advance
# Convert a string to a list of numbers
values = list(map(int, input_string.split()))
# "Slice" a one-dimensional list into lines of the required length
matrix = [values[i*cols : (i+1)*cols] for i in range(rows)]
Example of a problem with a two-dimensional array
Condition: Two two-dimensional arrays matrix1 and matrix2 of the same size are given. We need to create a third array result_matrix of the same size, in which each element will be equal to the largest of the elements at the corresponding positions in matrix1 and matrix2.
# Source arrays
matrix1 = [[1, 2], [3, 4]]
matrix2 = [[4, 3], [2, 1]]
# Initializing the resulting 2x2 array with zeros
result_matrix = [[0 for _ in range(2)] for _ in range(2)]
# Solution 1: Using the max() function is the most concise
for i in range(2):
for j in range(2):
result_matrix[i][j] = max(matrix1[i][j], matrix2[i][j])
# Output of the result
for row in result_matrix:
print(row)
# [4, 3]
# [3, 4]
You are already at the stage where you should understand that the same task can be solved in several ways. Knowing different approaches allows you to choose the most effective and readable one. Here are two more solutions to the same problem:
# Solution 2: Using the full if-else condition is the most understandable for beginners
for i in range(2):
for j in range(2):
if matrix1[i][j] > matrix2[i][j]:
result_matrix[i][j] = matrix1[i][j]
else:
result_matrix[i][j] = matrix2[i][j]
# Solution 3: Using the ternary operator - compact if-else replacement
for i in range(2):
for j in range(2):
result_matrix[i][j] = matrix1[i][j] if matrix1[i][j] > matrix2[i][j] else matrix2[i][j]
Detailed explanation:
- Initializing the resulting array: The construction
[[0 for _ in range(2)] for _ in range(2)] creates a 2x2 matrix filled with zeros. The inner part of [0 for _ in range(2)] creates a string [0, 0]. The outer loop repeats this action 2 times. The _ symbol is used as the name of a variable whose value is not important to us.
- Iterating through the elements: Nested loops
for at i and j ensure that we visit each cell [i][j] in both matrices simultaneously.
- Comparing elements: For each pair of elements
matrix1[i][j] and matrix2[i][j], we find the maximum value and write it to the same position [i][j] in result_matrix. The max() function does this most gracefully, but the logic with if-else is absolutely equivalent.
Final advice: Mastering nested loops and various ways of working with matrices is the key to solving a huge class of problems. Don't be afraid to experiment with different approaches. For very large matrices and complex mathematical operations, in the future you will get acquainted with the NumPy library, which makes such calculations incredibly fast. But for training and most standard tasks, the approaches described above are ideal.