The Portfolio
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
- L3
- Asked in
- Airbnb
Problem
A short-term rental marketplace exports its listings, one row per listing with a host and a bed count, and a single host can own several. We're publishing host standings, where a host's standing is the total beds across all of their listings. Produce the standings, biggest hosts first.
Count every bed under a name. The largest holdings rise first.
Example
Input:
listings = [{"beds":8,"host_id":"h2","host_name":"Bob"},{"beds":3,"host_id":"h1","host_name":"Alice"},{"beds":2,"host_id":"h3","host_name":"Carol"},{"beds":5,"host_id":"h1","host_name":"Alice"}]Output:
[{"rank":1,"host_name":"Alice","total_beds":8},{"rank":1,"host_name":"Bob","total_beds":8},{"rank":2,"host_name":"Carol","total_beds":2}]Worked solution and explanation
What this really is
Strip away the marketplace framing and this is a two-phase transform wearing a one-line 'rank the hosts' costume. Phase one collapses many listings into one row per host by summing beds; phase two walks those totals in order handing out positions. Anyone can sort a list. The first trap is that a host owns several listings, so positioning the rows as they arrive positions listings, not hosts, and a host with three small rooms leapfrogs a host with one big suite. The second trap: when two hosts tie, arbitrary input order decides who lands first unless you force host_name as the tie-break, so re-shuffling the input silently changes who sits at position 1.
Break it down
Step 1: Aggregate total beds per host
Fold the listings into a dict keyed by host_id, carrying the host_name and a running bed total. This is the step that makes the whole problem about hosts instead of rows.
Step 2: Sort by total, then break ties by name
Sort the aggregated hosts by total beds descending, then host_name ascending. The secondary key is not decoration: without it, two tied hosts come out in whatever order the dict happened to yield, and your output stops being deterministic.
Step 3: Assign no-gap positions
Walk the sorted hosts once, tracking the previous total. Bump the position only when the current total differs from the previous one. Equal totals reuse the current position, and the next distinct total gets the very next number, never skipping.
The solution
def rank_hosts(listings: list) -> list:
totals = {}
for row in listings:
hid = row['host_id']
if hid not in totals:
totals[hid] = {'host_name': row['host_name'], 'total_beds': 0}
totals[hid]['total_beds'] += row['beds']
ordered = sorted(
totals.values(),
key=lambda h: (-h['total_beds'], h['host_name']),
)
result = []
rank = 0
prev_total = None
for host in ordered:
if host['total_beds'] != prev_total:
rank += 1
prev_total = host['total_beds']
result.append({
'host_name': host['host_name'],
'total_beds': host['total_beds'],
'rank': rank,
})
return resultCommon follow-up questions
- How would you express this in SQL? (Tests SUM(beds) GROUP BY host_id with DENSE_RANK() OVER (ORDER BY SUM(beds) DESC).)
- How would the output change if the next distinct total should skip numbers equal to the size of the tie instead of continuing consecutively? (Tests understanding of gap behavior across the ranking family.)
- How would you compute this over a billion listings that arrive as a stream? (Tests scaling the aggregation when the listings will not fit in memory.)