diff --git a/data_structures/arrays/product_sum.py b/data_structures/arrays/product_sum.py index 4fb906f369ab..1d7d6ee94dbc 100644 --- a/data_structures/arrays/product_sum.py +++ b/data_structures/arrays/product_sum.py @@ -15,10 +15,12 @@ Example Input: [5, 2, [-7, 1], 3, [6, [-13, 8], 4]] -Output: 12 +Output: -12 """ +from timeit import timeit + def product_sum(arr: list[int | list], depth: int) -> int: """ @@ -92,7 +94,129 @@ def product_sum_array(array: list[int | list]) -> int: return product_sum(array, 1) +def product_sum_iterative(arr: list[int | list]) -> int: + """ + It Calculates the product sum of an array using iterative approach. + It's similar to BFS algorithm (Breadth first search algorithm). + It's won't run into stack overflow as compared to recursion approach + + Args: + array(List[Union[int, List]]): The array of integers/lists + + Returns: + int: The product sum of the array. + + Logic : + 1. Initialize a queue which stores the list, current + depth and it's multiplication factor + eg. queue -> [(arr, depth, multiplication_factor)] + + 2. Loop until queue is empty + 1. Take front item from Queue and pop it + 2. Iterate on front element + If current element is nested list + - then add that into queue with updated depth + and multiplication factor + Else if current element is not nested + - then update product sum variable by multiplying + current element with multiplicaton factor + + Algorithm flow example -> + Input list - [5, 2, [-7, 1], 3, [6, [-13, 8], 4]] + + Initialize queue - [([5, 2, [-7, 1], 3, [6, [-13, 8], 4]], 1, 1)] + + Step 0 + Queue - [([5, 2, [-7, 1], 3, [6, [-13, 8], 4]], 1, 1)] + Queue front item - + List - [5, 2, [-7, 1], 3, [6, [-13, 8], 4]] + depth - 1 + multiplication factor - 1 + + product sum = 0 (previous) + 5 * 1 + 2 * 1 + 3 * 1 = 10 + ------------------------------------------------------- + Step 1 + Queue - [([-7, 1], 2, 2), ([6, [-13, 8], 4], 2, 2)] + Queue front item - + List - [-7, 1] + depth - 2 + multiplication factor - 2 + + product sum = 10 (previous) + (-7) * 2 + 1 * 2 = -2 + ------------------------------------------------------- + Step 2 + Queue - [([6, [-13, 8], 4], 2, 2)] + Queue front item - + List - [6, [-13, 8], 4] + depth - 2 + multiplication factor - 2 + + product sum = -2 (previous) + 6 * 2 + 4 * 2 = 18 + ------------------------------------------------------- + Step 3 + Queue - [([-13, 8], 3, 6)] + Queue front item - + List - [-13, 8] + depth - 3 + multiplication factor - 6 + + product sum = 18 (previous) + (-13) * 6 + 8 * 6 = -12 + ------------------------------------------------------- + + Examples: + >>> product_sum_array([1, 2, 3]) + 6 + >>> product_sum_array([1, [2, 3]]) + 11 + >>> product_sum_array([1, [2, [3, 4]]]) + 47 + >>> product_sum_array([0]) + 0 + >>> product_sum_array([-3.5, [1, [0.5]]]) + 1.5 + >>> product_sum_array([1, -2]) + -1 + """ + + # Initialize queue with depth and multiplication factor + queue = [(arr, 1, 1)] + + product_sum = 0 + + while queue: + queue_front_list, depth, multiplication_factor = queue.pop(0) + + for element in queue_front_list: + if isinstance(element, list): + queue.append((element, depth + 1, multiplication_factor * (depth + 1))) + else: + product_sum += element * multiplication_factor + + return product_sum + + +def benchmark() -> None: + """ + Benchmark code comparing different version. + """ + + setup = "from __main__ import product_sum_array, product_sum_iterative" + + print( + timeit("product_sum_array([5, 2, [-7, 1], 3, [6, [-13, 8], 4]])", setup=setup) + ) + # 1.1448657000437379 + + print( + timeit( + "product_sum_iterative([5, 2, [-7, 1], 3, [6, [-13, 8], 4]])", setup=setup + ) + ) + # 1.6824490998405963 + + if __name__ == "__main__": import doctest doctest.testmod() + benchmark()