Points of Order
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
Problem
A web-analytics rollup hands you views, a dict mapping each page path to its view count for the day. Return a [path, count] pair for every page, ordered from the most-viewed page down to the least. When two pages drew the same number of views, the one whose path comes first alphabetically goes ahead.
Every page makes its case for the top. Settle it, and settle the ties.
Example 1
Input:
views = {"/home":3,"/about":1,"/pricing":2}Output:
[["/home",3],["/pricing",2],["/about",1]]
Example 2
Input:
views = {"/blog":5,"/cart":2,"/login":5}Output:
[["/blog",5],["/login",5],["/cart",2]]
Worked solution and explanation
What this really is
This is a two-key sort wearing a leaderboard costume. The counts sort one way, biggest first. The paths sort the other way, alphabetical and smallest first, but only when counts tie. That opposition is the entire problem. The lazy answer, sorted(items, reverse=True), flips BOTH directions at once: it does give you counts high-to-low, but it also reverses the path order on ties, so two pages tied at 5 views come back as /login before /blog instead of /blog before /login. It sails through every example without a tie and breaks the instant one appears.
The move that cracks it
Step 1: Materialize the pairs
Build the output rows first: one [path, count] pair per entry in views. A small comprehension over views.items() is the clean way, and it leaves the original dict untouched.
Step 2: Sort on a composite key
Sort with a tuple key (-count, path). Negating the count gives you descending order on the numbers while keeping the natural ascending order on the path. Python compares the tuple left to right, so path only matters when the negated counts are equal. One sort, both rules.
def rank_pages(views):
return sorted(
([path, count] for path, count in views.items()),
key=lambda pair: (-pair[1], pair[0]),
)- reverse=True (wrong on ties)
- sorted(pairs, key=lambda p: p[1], reverse=True). Ties at 5: /login, /blog. The reverse flag dragged the path order backwards.
- tuple key (correct)
- sorted(pairs, key=lambda p: (-p[1], p[0])). Ties at 5: /blog, /login. Count descends, path still ascends.
Common follow-up questions
- What if you only need the top 10 pages instead of the full ordering? (Pushes toward heapq.nlargest(k, views.items(), key=lambda p: p[1]) for O(n log k), and a discussion of how to keep the same tie-break under a heap.)
- How does your tie-break survive if you switch to a heap-based top-k? (Tests whether the candidate sees that a plain heap or nlargest does not honor the secondary ascending key without extra care.)
- What changes if the view counts stream in and update throughout the day? (Tests maintaining order incrementally with a structure like a SortedList rather than re-sorting on every change.)