Evaluate Configurable Rideshare Payout Audit Rules as Data
RipplingSoftware Engineer · Technical ScreenLast updated
Implement a generic rule-evaluation engine for a rideshare payout audit tool, where per-fare and per-driver-total rules, each with its own AND-combined conditions, are supplied entirely as data rather than hard-coded branches, using exact integer-cent arithmetic.
A rideshare payout audit tool flags fares and drivers that trip configurable policies — e.g., "any airport fare over $10," or "a driver whose total surge-zone earnings this batch exceed $30." New policies are added by finance without a code change, so the rules must be evaluated as data, not as a hard-coded if per policy.
Implement evaluate_payout_rules(fares, rules, conditions) -> list[list[str]].
Input contract
Every dollar figure is tracked in whole cents rather than a decimal currency type, which would otherwise accumulate rounding drift across repeated additions. The table representation and operator set below are fixed for this exercise.
- Each fare is
[fareId, driverId, amountCents, fareType, zoneType, zoneName]. Fare IDs are unique; every field is present. Up to 10,000 fares, 100 rules, 1,000 conditions.amountCentsis a nonnegative integer string, at most 100,000,000. - Each rule is
[policyId, scope, capCents], with uniquepolicyId.scopeisFAREorDRIVER_SUM. ForFARE,capCentsis the empty string and unused. ForDRIVER_SUM, it's a nonnegative integer string. - Each condition is
[policyId, field, operator, value]. Conditions sharing apolicyIdare combined with AND. A rule with zero conditions matches every fare. Every condition references a rule that exists. - Valid fields:
fare_id,driver_id,amount_cents,fare_type,zone_type,zone_name. - For
amount_cents: operatorsEQ, NE, GT, GE, LT, LE, compared as integers. For every other field: operatorsEQ, NEonly, compared as exact, case-sensitive strings. Input is always well-formed. - A
FARErule flags every matching fare individually. ADRIVER_SUMrule sumsamountCentsof matching fares per driver, then flags a driver only if that driver's sum is strictly greater than the threshold. A driver with no matching fares has sum zero and is never flagged, since thresholds are nonnegative.
Output contract
Return one row [scope, subjectId, policyId, actualCents] per violation. subjectId is a fare ID or a driver ID. actualCents is that fare's amount, or the driver's filtered sum, as an integer string. Order the output by rule input order; within a FARE rule, by fare input order; within a DRIVER_SUM rule, by driverId ascending (lexicographic).
Worked example
fares = [
["F1","D1","1200","airport","surge","downtown"],
["F2","D1","900","standard","normal","suburb"],
["F3","D2","5000","airport","normal","downtown"],
["F4","D2","300","standard","normal","suburb"],
["F5","D1","2200","airport","surge","downtown"],
]
rules = [
["R1","FARE",""], # airport fares over 1000 cents
["R2","DRIVER_SUM","3000"], # per-driver sum of surge-zone fares over 3000 cents
]
conditions = [
["R1","fare_type","EQ","airport"],
["R1","amount_cents","GT","1000"],
["R2","zone_type","EQ","surge"],
]
Expected output:
[["FARE","F1","R1","1200"],
["FARE","F3","R1","5000"],
["FARE","F5","R1","2200"],
["DRIVER_SUM","D1","R2","3400"]]
D1's surge total is 1200 + 2200 = 3400 > 3000, so it's flagged; D2 has no surge fares at all.
Hints
Hint 1
Model a condition as a (field, operator) pair resolved to a comparator function at setup time, so evaluating a fare against a rule is just 'all comparators pass,' with no per-field branching scattered through the main loop.
Hint 2
Keep amount comparisons as integers end to end — never format cents as a float or a currency string before the comparison.
Hint 3
Group conditions by policyId once, up front, rather than re-scanning the whole conditions list for every fare.
Hint 4
For DRIVER_SUM, accumulate a running sum per driver in one pass over the fares that match the rule's conditions, then filter and sort the accumulated sums separately from the matching step.
Follow-up questions
- How would you extend this to support an OR between some conditions, not just AND across all of a rule's conditions?
- If this needed to run incrementally as fares stream in throughout the day rather than as one batch, what would need to change about the DRIVER_SUM accounting?
- How would you add a new scope, say ZONE_SUM, without duplicating the FARE-matching logic?
- What would you change about the condition representation to let a rule reference a derived field, like 'fare count this week for this driver', not just columns present on the fare itself?
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.