Evaluate Symbol Expressions
HarveySoftware Engineer · OnsiteLast updated
Implement an expression evaluator for a dictionary of symbolic definitions with arithmetic operations, resolving dependencies, and detecting cycles and undefined references.
Problem Statement
You are building a lightweight formula engine. You are given a dictionary expressions where each key is a variable name (a string of alphanumeric characters) and each value is an arithmetic expression as a string.
An expression is composed of:
- Non-negative integer literals (e.g.,
"42") - Variable names referencing other keys in the dictionary
- Binary operators:
+,-, and* - Spaces separating tokens
Your task is to write a function evaluate_expressions(expressions: dict[str, str]) -> dict[str, int] that returns a dictionary mapping each variable name to its fully evaluated integer value.
Requirements
- Operator Precedence: Standard arithmetic precedence applies (
*has higher precedence than+and-). Operations with equal precedence evaluate from left to right. - Dependency Resolution: A variable may reference other variables. Dependencies must be evaluated dynamically or resolved in topological order.
- Error Handling:
- If an expression references a variable not defined in
expressions, raise aValueError("Undefined variable: "). - If there is a circular dependency (e.g.,
Adepends onBandBdepends onA), raise aValueError("Circular dependency detected").
- If an expression references a variable not defined in
Function Signature
def evaluate_expressions(expressions: dict[str, str]) -> dict[str, int]:
pass
Examples
Example 1:
expressions = {
"A": "3 + 2",
"B": "A * 4",
"C": "B - 2 + A"
}
output = evaluate_expressions(expressions)
# Output:
# {
# "A": 5,
# "B": 20,
# "C": 23
# }
Explanation: A evaluates to 5. B evaluates to 5 * 4 = 20. C evaluates to 20 - 2 + 5 = 23.
Example 2:
expressions = {
"x": "y + 1",
"y": "x * 2"
}
# Raises ValueError("Circular dependency detected")
Example 3:
expressions = {
"total": "base_price + tax",
"base_price": "100"
}
# Raises ValueError("Undefined variable: tax")
Constraints
1 <= len(expressions) <= 10^4- Each variable name consists of lowercase and uppercase letters, digits, and underscores.
- Expression length is between 1 and 200 characters.
- Operands and operators in expression strings are guaranteed to be separated by single spaces.
- Values will not exceed standard 64-bit integer limits during evaluation.
Hints
Hint 1
Model the variable relationships as a directed graph where an edge exists from variable X to variable Y if X's expression references Y.
Hint 2
Use a three-state Depth-First Search (unvisited, visiting, visited) to detect cycles and memoize already computed variable values.
Hint 3
For evaluating arithmetic strings with precedence, use a standard two-stack approach or convert the expression into postfix notation (Reverse Polish Notation).
Follow-up questions
- How would you handle parentheses in expressions, and how does that affect your parser?
- If expressions are updated dynamically one at a time, how would you minimize recomputations instead of re-evaluating everything from scratch?
- How would you extend this system to evaluate independent subtrees concurrently across multiple worker threads?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.