Footprints in the Feed
A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- medium
- Seniority
- L4
Problem
You're rolling up raw feed-handler log lines in lines, each a CSV row of date,process,host,log_message,bytes, where the process name carries the exchange as its leading token (so nyse_feed_handler is an NYSE process and nasdaq_market_data is a NASDAQ one). Roll the byte counts up two ways in one pass: total bytes per day, and total bytes per exchange within each day. Return both rollups together, the per-day totals first.
Every trade left a footprint.
Example 1
Input:
lines = ["2024-01-15,nyse_feed_handler,srv1,trade executed,1024","2024-01-15,nasdaq_market_data,srv2,quote update,2048","2024-01-15,nyse_order_router,srv1,order routed,512","2024-01-16,nasdaq_feed_handler,srv2,trade executed,4096"]
Output:
[{"2024-01-15":3584,"2024-01-16":4096},{"2024-01-15":{"nyse":1536,"nasdaq":2048},"2024-01-16":{"nasdaq":4096}}]Example 2
Input:
lines = []
Output:
[{},{}]Worked solution and explanation
What this problem really is
This is a two-dimensional rollup wearing a log-parsing costume. The parsing (split a comma row, grab the token before the first underscore) is the part everyone gets right. The skill actually being probed: can you accumulate a per-day total AND a per-exchange-within-day total in the SAME pass, where the second result is a dict of dicts you grow lazily as new (date, exchange) pairs show up. The trap is quietly expensive: candidates build one accumulator, or roll up only by day, then discover they have collapsed the exchange dimension into a single sum and cannot get it back. Once bytes from nyse and nasdaq land in the same per-day number, no later step can split them apart.
Break down the requirements
Step 1: Parse each CSV line into fields
Split on comma to get date, process, host, log_message, and bytes. Convert the bytes field with int(...). The host and log_message columns are noise for this task; you only touch positions 0, 1, and 4.
Step 2: Extract the exchange name from the process field
The exchange name is the portion before the first underscore in the process column: process.split('_')[0]. Note that a process with no underscore (like cme) returns the whole string unchanged, which is exactly the behavior you want.
Step 3: Accumulate bytes by day and by exchange-day
Keep two dicts side by side and update BOTH on every line, not one then the other in a second pass. daily_totals[date] accumulates a scalar; exchange_daily[date] is itself a dict that must exist before you index into it, so initialize it the first time you see a new date. Return them in a list in that exact order: [daily_totals, exchange_daily].
The solution
def aggregate_trades(lines: list) -> list:
daily_totals = {}
exchange_daily = {}
for line in lines:
parts = line.split(",")
date = parts[0]
process = parts[1]
bytes_val = int(parts[4])
exchange = process.split("_")[0]
daily_totals[date] = daily_totals.get(date, 0) + bytes_val
if date not in exchange_daily:
exchange_daily[date] = {}
exchange_daily[date][exchange] = exchange_daily[date].get(exchange, 0) + bytes_val
return [daily_totals, exchange_daily]One pass, both rollups updated together so the exchange dimension is never collapsed.
Common follow-up questions
- How would you handle quoted CSV fields containing commas? (Tests using the `csv` module instead of naive `split(',')`.)
- Does your answer change if logs arrive out of chronological order? (Tests whether the candidate realizes dict aggregation is order-independent.)
- How would you process a 10GB log file? (Tests streaming line-by-line processing instead of loading the entire file.)
- What if the process field had no underscore? (Tests defensive parsing with a fallback when `split('_')` yields only one part.)