Menu iconMenu iconAlgorithms and Data Structures with Python
Algorithms and Data Structures with Python

Chapter 11: From Theory to Practice. Case Studies & Optimizations

Chapter 11: Practical Exercises of From Theory to Practice. Case Studies & Optimizations

The following exercises provide practical opportunities to delve into and enhance Python code for superior performance and efficiency. They cover a range of situations, including refining sorting algorithms, managing extensive datasets, and applying parallel processing techniques. These exercises are designed to mirror actual coding challenges you may encounter.

Exercise 1: Optimizing a Sorting Function

  • Objective: Improve the performance of a Python sorting function.
  • Task: Implement a custom sorting function and then optimize it using built-in Python functionalities.

Solution:

# Initial Custom Sorting Function
def custom_sort(arr):
    for i in range(len(arr)):
        for j in range(i + 1, len(arr)):
            if arr[i] > arr[j]:
                arr[i], arr[j] = arr[j], arr[i]
    return arr

# Optimized Sorting Using Built-in Sort
def optimized_sort(arr):
    return sorted(arr)

# Example Usage
arr = [3, 1, 4, 1, 5, 9, 2, 6]
print("Custom Sort:", custom_sort(arr.copy()))
print("Optimized Sort:", optimized_sort(arr.copy()))

Exercise 2: Memory Optimization in Data Processing

  • Objective: Optimize a Python function for memory usage.
  • Task: Rewrite a function that processes a large dataset to be more memory-efficient using generators.

Solution:

# Initial Memory-Intensive Function
def process_data(data):
    results = []
    for item in data:
        results.append(item * 2)  # Some processing
    return results

# Memory-Optimized Function Using Generators
def optimized_process_data(data):
    for item in data:
        yield item * 2

# Example Usage
large_data = range(1000000)
print("Memory-Optimized Processing:")
for result in optimized_process_data(large_data):
    pass  # Replace with actual use of 'result'

Exercise 3: Parallelizing a Computation-Intensive Task

  • Objective: Use Python’s multiprocessing to optimize a computation-intensive task.
  • Task: Modify a function that performs a CPU-bound operation to utilize multiple cores.

Solution:

from multiprocessing import Pool

def compute_square(n):
    return n * n

def parallel_square(numbers):
    with Pool(4) as pool:
        return pool.map(compute_square, numbers)

# Example Usage
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print("Parallel Square Computation:", parallel_square(numbers))

Exercise 4: Profiling and Optimizing Python Code

  • Objective: Profile a Python script and identify bottlenecks.
  • Task: Use cProfile to profile the given function and then optimize it.

Initial Function:

def find_primes(n):
    primes = []
    for num in range(2, n + 1):
        prime = True
        for i in range(2, num):
            if (num % i) == 0:
                prime = False
                break
        if prime:
            primes.append(num)
    return primes

# Profiling
import cProfile
cProfile.run('find_primes(1000)')

Optimized Function:

def optimized_find_primes(n):
    primes = []
    for num in range(2, n + 1):
        if all(num % i != 0 for i in range(2, int(num**0.5) + 1)):
            primes.append(num)
    return primes

# Example Usage and Profiling
cProfile.run('optimized_find_primes(1000)')

Chapter 11: Practical Exercises of From Theory to Practice. Case Studies & Optimizations

The following exercises provide practical opportunities to delve into and enhance Python code for superior performance and efficiency. They cover a range of situations, including refining sorting algorithms, managing extensive datasets, and applying parallel processing techniques. These exercises are designed to mirror actual coding challenges you may encounter.

Exercise 1: Optimizing a Sorting Function

  • Objective: Improve the performance of a Python sorting function.
  • Task: Implement a custom sorting function and then optimize it using built-in Python functionalities.

Solution:

# Initial Custom Sorting Function
def custom_sort(arr):
    for i in range(len(arr)):
        for j in range(i + 1, len(arr)):
            if arr[i] > arr[j]:
                arr[i], arr[j] = arr[j], arr[i]
    return arr

# Optimized Sorting Using Built-in Sort
def optimized_sort(arr):
    return sorted(arr)

# Example Usage
arr = [3, 1, 4, 1, 5, 9, 2, 6]
print("Custom Sort:", custom_sort(arr.copy()))
print("Optimized Sort:", optimized_sort(arr.copy()))

Exercise 2: Memory Optimization in Data Processing

  • Objective: Optimize a Python function for memory usage.
  • Task: Rewrite a function that processes a large dataset to be more memory-efficient using generators.

Solution:

# Initial Memory-Intensive Function
def process_data(data):
    results = []
    for item in data:
        results.append(item * 2)  # Some processing
    return results

# Memory-Optimized Function Using Generators
def optimized_process_data(data):
    for item in data:
        yield item * 2

# Example Usage
large_data = range(1000000)
print("Memory-Optimized Processing:")
for result in optimized_process_data(large_data):
    pass  # Replace with actual use of 'result'

Exercise 3: Parallelizing a Computation-Intensive Task

  • Objective: Use Python’s multiprocessing to optimize a computation-intensive task.
  • Task: Modify a function that performs a CPU-bound operation to utilize multiple cores.

Solution:

from multiprocessing import Pool

def compute_square(n):
    return n * n

def parallel_square(numbers):
    with Pool(4) as pool:
        return pool.map(compute_square, numbers)

# Example Usage
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print("Parallel Square Computation:", parallel_square(numbers))

Exercise 4: Profiling and Optimizing Python Code

  • Objective: Profile a Python script and identify bottlenecks.
  • Task: Use cProfile to profile the given function and then optimize it.

Initial Function:

def find_primes(n):
    primes = []
    for num in range(2, n + 1):
        prime = True
        for i in range(2, num):
            if (num % i) == 0:
                prime = False
                break
        if prime:
            primes.append(num)
    return primes

# Profiling
import cProfile
cProfile.run('find_primes(1000)')

Optimized Function:

def optimized_find_primes(n):
    primes = []
    for num in range(2, n + 1):
        if all(num % i != 0 for i in range(2, int(num**0.5) + 1)):
            primes.append(num)
    return primes

# Example Usage and Profiling
cProfile.run('optimized_find_primes(1000)')

Chapter 11: Practical Exercises of From Theory to Practice. Case Studies & Optimizations

The following exercises provide practical opportunities to delve into and enhance Python code for superior performance and efficiency. They cover a range of situations, including refining sorting algorithms, managing extensive datasets, and applying parallel processing techniques. These exercises are designed to mirror actual coding challenges you may encounter.

Exercise 1: Optimizing a Sorting Function

  • Objective: Improve the performance of a Python sorting function.
  • Task: Implement a custom sorting function and then optimize it using built-in Python functionalities.

Solution:

# Initial Custom Sorting Function
def custom_sort(arr):
    for i in range(len(arr)):
        for j in range(i + 1, len(arr)):
            if arr[i] > arr[j]:
                arr[i], arr[j] = arr[j], arr[i]
    return arr

# Optimized Sorting Using Built-in Sort
def optimized_sort(arr):
    return sorted(arr)

# Example Usage
arr = [3, 1, 4, 1, 5, 9, 2, 6]
print("Custom Sort:", custom_sort(arr.copy()))
print("Optimized Sort:", optimized_sort(arr.copy()))

Exercise 2: Memory Optimization in Data Processing

  • Objective: Optimize a Python function for memory usage.
  • Task: Rewrite a function that processes a large dataset to be more memory-efficient using generators.

Solution:

# Initial Memory-Intensive Function
def process_data(data):
    results = []
    for item in data:
        results.append(item * 2)  # Some processing
    return results

# Memory-Optimized Function Using Generators
def optimized_process_data(data):
    for item in data:
        yield item * 2

# Example Usage
large_data = range(1000000)
print("Memory-Optimized Processing:")
for result in optimized_process_data(large_data):
    pass  # Replace with actual use of 'result'

Exercise 3: Parallelizing a Computation-Intensive Task

  • Objective: Use Python’s multiprocessing to optimize a computation-intensive task.
  • Task: Modify a function that performs a CPU-bound operation to utilize multiple cores.

Solution:

from multiprocessing import Pool

def compute_square(n):
    return n * n

def parallel_square(numbers):
    with Pool(4) as pool:
        return pool.map(compute_square, numbers)

# Example Usage
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print("Parallel Square Computation:", parallel_square(numbers))

Exercise 4: Profiling and Optimizing Python Code

  • Objective: Profile a Python script and identify bottlenecks.
  • Task: Use cProfile to profile the given function and then optimize it.

Initial Function:

def find_primes(n):
    primes = []
    for num in range(2, n + 1):
        prime = True
        for i in range(2, num):
            if (num % i) == 0:
                prime = False
                break
        if prime:
            primes.append(num)
    return primes

# Profiling
import cProfile
cProfile.run('find_primes(1000)')

Optimized Function:

def optimized_find_primes(n):
    primes = []
    for num in range(2, n + 1):
        if all(num % i != 0 for i in range(2, int(num**0.5) + 1)):
            primes.append(num)
    return primes

# Example Usage and Profiling
cProfile.run('optimized_find_primes(1000)')

Chapter 11: Practical Exercises of From Theory to Practice. Case Studies & Optimizations

The following exercises provide practical opportunities to delve into and enhance Python code for superior performance and efficiency. They cover a range of situations, including refining sorting algorithms, managing extensive datasets, and applying parallel processing techniques. These exercises are designed to mirror actual coding challenges you may encounter.

Exercise 1: Optimizing a Sorting Function

  • Objective: Improve the performance of a Python sorting function.
  • Task: Implement a custom sorting function and then optimize it using built-in Python functionalities.

Solution:

# Initial Custom Sorting Function
def custom_sort(arr):
    for i in range(len(arr)):
        for j in range(i + 1, len(arr)):
            if arr[i] > arr[j]:
                arr[i], arr[j] = arr[j], arr[i]
    return arr

# Optimized Sorting Using Built-in Sort
def optimized_sort(arr):
    return sorted(arr)

# Example Usage
arr = [3, 1, 4, 1, 5, 9, 2, 6]
print("Custom Sort:", custom_sort(arr.copy()))
print("Optimized Sort:", optimized_sort(arr.copy()))

Exercise 2: Memory Optimization in Data Processing

  • Objective: Optimize a Python function for memory usage.
  • Task: Rewrite a function that processes a large dataset to be more memory-efficient using generators.

Solution:

# Initial Memory-Intensive Function
def process_data(data):
    results = []
    for item in data:
        results.append(item * 2)  # Some processing
    return results

# Memory-Optimized Function Using Generators
def optimized_process_data(data):
    for item in data:
        yield item * 2

# Example Usage
large_data = range(1000000)
print("Memory-Optimized Processing:")
for result in optimized_process_data(large_data):
    pass  # Replace with actual use of 'result'

Exercise 3: Parallelizing a Computation-Intensive Task

  • Objective: Use Python’s multiprocessing to optimize a computation-intensive task.
  • Task: Modify a function that performs a CPU-bound operation to utilize multiple cores.

Solution:

from multiprocessing import Pool

def compute_square(n):
    return n * n

def parallel_square(numbers):
    with Pool(4) as pool:
        return pool.map(compute_square, numbers)

# Example Usage
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print("Parallel Square Computation:", parallel_square(numbers))

Exercise 4: Profiling and Optimizing Python Code

  • Objective: Profile a Python script and identify bottlenecks.
  • Task: Use cProfile to profile the given function and then optimize it.

Initial Function:

def find_primes(n):
    primes = []
    for num in range(2, n + 1):
        prime = True
        for i in range(2, num):
            if (num % i) == 0:
                prime = False
                break
        if prime:
            primes.append(num)
    return primes

# Profiling
import cProfile
cProfile.run('find_primes(1000)')

Optimized Function:

def optimized_find_primes(n):
    primes = []
    for num in range(2, n + 1):
        if all(num % i != 0 for i in range(2, int(num**0.5) + 1)):
            primes.append(num)
    return primes

# Example Usage and Profiling
cProfile.run('optimized_find_primes(1000)')