S1Q2 · Expand Sum of Products¶
⚡ Quick Reference
Function: expand_sum_of_products(expr: str) -> str
Core idea: strip spaces, extract the two bracketed groups, split each on +, then produce all four products.
def expand_sum_of_products(expr: str) -> str:
expr = expr.replace(" ", "")
# split on ")(" to get the two groups
left, right = expr[1:-1].split(")(")
a, b = left.split("+")
c, d = right.split("+")
return f"{a}*{c} + {a}*{d} + {b}*{c} + {b}*{d}"
Key rules:
- Strip spaces first with replace(" ", "")
- expr[1:-1] removes the outer ( and )
- Split on )( to separate the two factor groups
- Always exactly one + per group -guaranteed by problem
Problem Statement¶
Problem
Write a function expand_sum_of_products(expr) that expands "(a+b)(c+d)" into "a*c + a*d + b*c + b*d". Spaces may appear anywhere in the input and must be ignored.
Examples:
"(a+b)(c+d)"
"a*c + a*d + b*c + b*d"
"(1+5)(10+12)"
"1*10 + 1*12 + 5*10 + 5*12"
Understanding the problem¶
The expression always has the structure (a+b)(c+d). The goal is to apply the distributive law:
The trick is parsing the string correctly. After stripping spaces:
"(a+b)(c+d)"
Step 1 -remove outer chars: expr[1:-1] → "a+b)(c+d"
Step 2 -split on ")(" → ["a+b", "c+d"]
Step 3 -split each on "+" → a="a", b="b", c="c", d="d"
Step 4 -format output → "a*c + a*d + b*c + b*d"
expr[1:-1].split(')(')
After stripping spaces, the expression always starts with ( and ends with ). Removing both with [1:-1] gives "a+b)(c+d". Splitting this on )( neatly separates the two factor groups without needing regex.
Tracing the examples¶
"(a+b)(c+d)"
strip spaces → "(a+b)(c+d)"
[1:-1] → "a+b)(c+d"
split(")(") → ["a+b", "c+d"]
split("+") → a="a", b="b", c="c", d="d"
output → "a*c + a*d + b*c + b*d"
"(1+5)(10+12)"
strip spaces → "(1+5)(10+12)"
[1:-1] → "1+5)(10+12"
split(")(") → ["1+5", "10+12"]
split("+") → a="1", b="5", c="10", d="12"
output → "1*10 + 1*12 + 5*10 + 5*12"
Solution approaches¶
def expand_sum_of_products(expr: str) -> str:
# Remove all spaces
expr = expr.replace(" ", "")
# Remove outer parentheses and split into two groups
inner = expr[1:-1] # "a+b)(c+d"
group1, group2 = inner.split(")(")
# Extract individual terms
a, b = group1.split("+")
c, d = group2.split("+")
# Build the four products
terms = [f"{a}*{c}", f"{a}*{d}", f"{b}*{c}", f"{b}*{d}"]
return " + ".join(terms)
Building the terms as a list then joining with " + " makes the output format easy to adjust.
import re
def expand_sum_of_products(expr: str) -> str:
expr = expr.replace(" ", "")
# Extract content of each bracket
groups = re.findall(r'\(([^)]+)\)', expr)
a, b = groups[0].split("+")
c, d = groups[1].split("+")
return f"{a}*{c} + {a}*{d} + {b}*{c} + {b}*{d}"
re.findall(r'\(([^)]+)\)', expr) extracts the content inside each pair of brackets. More robust if the expression format were to vary, but overkill for this fixed structure.
from itertools import product
def expand_sum_of_products(expr: str) -> str:
expr = expr.replace(" ", "")
left, right = expr[1:-1].split(")(")
terms_l = left.split("+")
terms_r = right.split("+")
return " + ".join(
map(lambda pair: f"{pair[0]}*{pair[1]}", product(terms_l, terms_r))
)
itertools.product(terms_l, terms_r) generates all (a,c), (a,d), (b,c), (b,d) pairs in the correct order. map(lambda pair: ...) formats each pair. Scales naturally if either bracket had more than two terms.
Key takeaways¶
expr[1:-1].split(")(") to parse brackets
Removing outer brackets with slicing then splitting on )( is the cleanest way to separate two adjacent bracketed groups without regex.
" + ".join(terms) for output formatting
Build each product as a string in a list, then join with " + ". Cleaner than concatenating with hardcoded separators and easy to adapt.
itertools.product for Cartesian pairs
itertools.product(A, B) generates all (a, b) pairs -exactly what polynomial expansion requires. Use it when the number of terms per bracket might vary.