Repetition
Iteration
Iterative: Imagine you are stirring a pot of soup on the stove. You use a ladle or spoon to stir the soup in a continuous, repetitive motion. This is similar to an iterative approach, where you perform a specific action (stirring) repeatedly until a certain condition is met (like achieving the desired consistency). Iterate - do it again and again and
Iteration involves repeating a set of instructions until a specific condition is met. In other words, it uses loops to repeat a block of code for a certain number of times, or until a particular condition is satisfied. The most common types of iterations in Python are the "for" and "while" loops.
def iterative_stirring(times):
for _ in range(times):
print("Stirring soup")
# Example: Stir the soup 5 times iteratively
iterative_stirring(5)
Recursion
Recursive: Now, consider making a layered dish where you need to stir different components at different times. For instance, you stir a sauce, then switch to stirring a separate mixture, and perhaps repeat this process. Each stirring action is specific to a particular component, and you might need to revisit previous steps. This recursive-like approach involves performing distinct stirring tasks for different elements in a cyclical manner.
Recursion, on the other hand, involves a function calling itself repeatedly until a specific condition is met. Each recursive call reduces the problem into a smaller subproblem, until the base case is reached. Recursive functions are often used to solve problems that can be broken down into smaller subproblems, such as searching and sorting algorithms.
def recursive_stirring(components):
if not components:
return
current_component = components.pop(0)
print(f"Stirring {current_component}")
recursive_stirring(components)
# Example: Stir different components recursively
components_to_stir = ["sauce", "mixture", "others"]
recursive_stirring(components_to_stir)
In the iterative example, the soup is stirred a specified number of times. In the recursive example, different components are stirred one after another until there are no more components to stir. The recursive function calls itself for each component, creating a cyclical pattern.
In summary, the iterative stirring is a continuous repetition, while the recursive stirring involves distinct stirring actions for different components in a cyclical fashion.
Examples
Iterative and Recursive Subtraction
def iterate(number):
for i in range(number, 0, -1):
print(i)
iterate(9)
def recur(number):
if number == 0: #base case
return 0
else:
print(number)
return recur(number - 1)
recur(9)
Iterative and Recursive Addition
def iterate(number):
for i in range(0, number, +1):
print(i)
iterate(9)
def recur(number):
if number == 10: #base case
return 10
else:
print(number)
return recur(number + 1)
recur(1)
If we reach the base case, then you are done, otherwise call the function with a manipulated version of the current value
Iterative and Recursive Walking
def walk(steps):
for step in range(1, steps+1):
print(f"You took {step} steps")
walk(10)
def walk(steps):
if steps == 0:
return
walk(steps - 1)
print(f"You took {steps} steps")
walk(10)
Iterative and Recursive Factorial
# iterative function to calculate the factorial of a number
def factorial_iterative(n):
result = 1
for i in range(1, n+1):
result *= i
return result
# example usage
print(factorial_iterative(5)) # Output: 120
# recursive function to calculate the factorial of a number
def factorial_recursive(n):
if n == 1:
return 1
else:
return n * factorial_recursive(n-1)
# example usage
print(factorial_recursive(5)) # Output: 120
Recurse over dictionaries or files
def get_inner_dict(d):
for _, v in d.items():
if isinstance(v, dict):
return get_inner_dict(v)
else:
return d
print(get_inner_dict({'key':{'name': {'same': {'justic': 'peace'}}}}))
import os
def list_files_in_directory(directory):
for root, dirs, files in os.walk(directory):
print(f"Current directory: {root}")
# Print all files in the current directory
for file in files:
print(f"File: {os.path.join(root, file)}")
# If you want to do something with directories, you can iterate over 'dirs' as well
# for dir_name in dirs:
# print(f"Subdirectory: {os.path.join(root, dir_name)}")
# Example: List all files in the current directory and its subdirectories
list_files_in_directory('.')
Your Turn
Navigate a maze
def navigate_maze(maze, start, end):
rows = len(maze)
cols = len(maze[0])
def is_valid_move(row, col):
return 0 <= row < rows and 0 <= col < cols and maze[row][col] == 0
def solve(row, col):
if row == end[0] and col == end[1]:
return True # Found the exit
if is_valid_move(row, col):
# Mark the current cell as visited
maze[row][col] = 2
# Try moving in all four directions: up, down, left, right
if solve(row - 1, col) or solve(row + 1, col) or solve(row, col - 1) or solve(row, col + 1):
return True
# If none of the paths lead to the exit, backtrack
maze[row][col] = 0
return False
start_row, start_col = start
if solve(start_row, start_col):
print("Solution found!")
for row in maze:
print(row)
else:
print("No solution found.")
# Example maze (0 represents open path, 1 represents a wall)
maze = [
[0, 1, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 0, 1, 1, 0],
[0, 1, 0, 1, 0],
[0, 0, 0, 0, 0]
]
start_point = (0, 0)
end_point = (4, 4)
navigate_maze(maze, start_point, end_point)
Details
This recursive function uses a depth-first search approach to explore the maze. It marks visited cells as it moves and backtracks when necessary. Note that this is a simple example, and you may need to adapt it based on the specifics of your maze structure and requirements.
Let me explain how the recursive maze navigation function works:
- Initialization:
- The
navigate_maze
function takes three parameters:maze
,start
, andend
.maze
is a 2D array representing the maze, where 0 represents an open path, and 1 represents a wall.start
andend
are the starting and ending points in the form of (row, column) tuples. - The function then defines two helper functions:
is_valid_move
to check if a move is within the bounds of the maze and onto an open path, andsolve
which recursively explores the maze.
- The
- Base Case:
- The
solve
function's base case checks if the current position(row, col)
is equal to theend
point. If true, it means we have reached the exit, and the function returnsTrue
.
- The
- Recursive Exploration:
- If the current position is a valid move, the function marks the current cell as visited by setting
maze[row][col] = 2
. - Then, it recursively explores all four possible directions (up, down, left, right) by calling itself with the updated positions.
- If any of the recursive calls return
True
, it means a valid path to the exit is found, and the function returnsTrue
.
- If the current position is a valid move, the function marks the current cell as visited by setting
- Backtracking:
- If none of the recursive calls find a valid path, the function backtracks by setting the current cell back to 0 (open path) before returning
False
.
- If none of the recursive calls find a valid path, the function backtracks by setting the current cell back to 0 (open path) before returning
- Starting the Search:
- The function starts the recursive search from the
start
position and prints whether a solution is found or not.
- The function starts the recursive search from the
- Example:
- The example maze has a start at (0, 0) and an exit at (4, 4). The function explores the maze recursively, marking visited cells as it goes, until it finds a path to the exit or exhausts all possibilities.
Remember, this is a basic example, and real-world scenarios may require additional considerations and optimizations. The key concept is recursive exploration and backtracking in the context of a maze-solving algorithm.