Reconstruct Each User's Journey from Unordered Activity Logs

Quick Overview

Given unordered user activity log entries, each holding a user id, a timestamp and an action, rebuild every user's journey as the list of their actions in time order. The task tests grouping by user, stable sorting with numeric timestamp comparison, and a deterministic output order across users.

Reconstruct Each User's Journey from Unordered Activity Logs

Company: Whatnot

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: hard

Interview Round: Onsite

An app writes one log entry for every user action, and the entries reach you in no particular order. Each entry records which user acted, when, and what they did. Reconstruct every user's journey: that user's actions in the order in which they happened. ### Function Signature ```python def reconstruct_journeys(logs: list[list[str]]) -> list[list[str]]: ``` ### Rules - `logs[i] = [user_id, timestamp, action]`. All three fields are strings, exactly as read from a log file; `timestamp` is a non-negative integer written in decimal. - A user's journey is that user's actions ordered by timestamp, earliest first. Compare timestamps as integers, not as strings, so `"9"` comes before `"10"`. - Two entries of the same user with the same timestamp keep the relative order they have in `logs`. - Every entry contributes one action, so a journey can contain the same action more than once. - Return one list per distinct user: `[user_id, action_1, action_2, ..., action_k]`. Order these lists by `user_id` in ascending lexicographic order (plain character-code comparison, so `"u10"` comes before `"u9"`). - Return `[]` when `logs` is empty. ### Constraints - `0 <= len(logs) <= 10^5` - `user_id` has 1 to 20 characters, each a lowercase English letter or a digit. - `action` has 1 to 30 characters, each a lowercase English letter or an underscore. - `timestamp` is the decimal form of an integer `0 <= timestamp <= 10^12` (for example, milliseconds since the Unix epoch), with no leading zeros (`"0"` itself is allowed). Values can exceed 2^31-1, so parse them into 64-bit integers. ### Examples **Example 1** ```text Input: logs = [["u2", "5", "view_item"], ["u1", "3", "login"], ["u2", "1", "login"], ["u1", "10", "logout"], ["u1", "7", "search"]] Output: [["u1", "login", "search", "logout"], ["u2", "login", "view_item"]] ``` User `u1` acted at times 3, 7 and 10; `"10"` is the latest even though it would sort first as a string. User `u2` acted at times 1 and 5. **Example 2** ```text Input: logs = [["b7", "4", "add_to_cart"], ["a1", "2", "open_app"], ["b7", "4", "checkout"], ["b7", "1", "open_app"]] Output: [["a1", "open_app"], ["b7", "open_app", "add_to_cart", "checkout"]] ``` User `b7` has two entries at time 4; `add_to_cart` comes before `checkout` because it appears first in `logs`. **Example 3** ```text Input: logs = [] Output: [] ```

Overview: Given unordered user activity log entries, each holding a user id, a timestamp and an action, rebuild every user's journey as the list of their actions in time order. The task tests grouping by user, stable sorting with numeric timestamp comparison, and a deterministic output order across users.

Whatnot logo
Whatnot
Aug 14, 2026
hardSoftware EngineerOnsiteCoding & Algorithms
0
0

An app writes one log entry for every user action, and the entries reach you in no particular order. Each entry records which user acted, when, and what they did. Reconstruct every user's journey: that user's actions in the order in which they happened.

Function Signature

def reconstruct_journeys(logs: list[list[str]]) -> list[list[str]]:

Rules

  • logs[i] = [user_id, timestamp, action] . All three fields are strings, exactly as read from a log file; timestamp is a non-negative integer written in decimal.
  • A user's journey is that user's actions ordered by timestamp, earliest first. Compare timestamps as integers, not as strings, so "9" comes before "10" .
  • Two entries of the same user with the same timestamp keep the relative order they have in logs .
  • Every entry contributes one action, so a journey can contain the same action more than once.
  • Return one list per distinct user: [user_id, action_1, action_2, ..., action_k] . Order these lists by user_id in ascending lexicographic order (plain character-code comparison, so "u10" comes before "u9" ).
  • Return [] when logs is empty.

Constraints

  • 0 <= len(logs) <= 10^5
  • user_id has 1 to 20 characters, each a lowercase English letter or a digit.
  • action has 1 to 30 characters, each a lowercase English letter or an underscore.
  • timestamp is the decimal form of an integer 0 <= timestamp <= 10^12 (for example, milliseconds since the Unix epoch), with no leading zeros ( "0" itself is allowed). Values can exceed 2^31-1, so parse them into 64-bit integers.

Examples

Example 1

Input:  logs = [["u2", "5", "view_item"], ["u1", "3", "login"], ["u2", "1", "login"],
                ["u1", "10", "logout"], ["u1", "7", "search"]]
Output: [["u1", "login", "search", "logout"], ["u2", "login", "view_item"]]

User u1 acted at times 3, 7 and 10; "10" is the latest even though it would sort first as a string. User u2 acted at times 1 and 5.

Example 2

Input:  logs = [["b7", "4", "add_to_cart"], ["a1", "2", "open_app"], ["b7", "4", "checkout"],
                ["b7", "1", "open_app"]]
Output: [["a1", "open_app"], ["b7", "open_app", "add_to_cart", "checkout"]]

User b7 has two entries at time 4; add_to_cart comes before checkout because it appears first in logs.

Example 3

Input:  logs = []
Output: []