FastPrepBuild Sessions from Unordered Events (Part 1)

Build Sessions from Unordered Events (Part 1)

Scale AI logoScale AI● MediumNEW GRADINTERNOA

Problem statement

This is Part 1 of Event Log Reconciliation. Continue with Part 2: Match Billing Charges to User Sessions for billing reconciliation.

Background

You receive a stream of user activity events. The events may arrive out of order. In Part 1, reconstruct the user sessions and summarize them for each user.

events is a list of objects. Each object has a user ID, an integer timestamp, and an event type:

{ "user": "u1", "ts": 100, "type": "login" }

The type is login, action, or logout. A single user's events have distinct timestamps. Events from different users may have the same timestamp.

How to build sessions

Process the events for each user in timestamp order:

  • A login opens a session.
  • The next logout for that user closes the session. Its active time is logout_ts - login_ts.
  • Missing logout: If another login arrives while the session is open, or the user's events end before a logout, close the session at its last action timestamp. If it contains no actions, close it at its login timestamp, giving it an active time of 0. A new login then opens another session.
  • Ignore an action or logout when the user has no open session. For example, an action before the first login belongs to no session.

Session summaries

The result is a mapping from each user to that user's session summary:

{"u1": { "sessions": 2, "active_time": 300 }}
  • sessions is the number of sessions reconstructed for the user, including sessions with zero active time.
  • active_time adds end - start across that user's sessions.

Leave out users who have no reconstructed sessions.

Walkthrough

Consider these events:

[{ "user": "u1", "ts": 100, "type": "login" },{ "user": "u1", "ts": 250, "type": "logout" },{ "user": "u1", "ts": 180, "type": "action" },{ "user": "u2", "ts": 120, "type": "action" }]

The u1 action arrives after its logout in the input. In timestamp order, the events are login at 100, action at 180, and logout at 250. They form one session, [100, 250], with active time 150.

User u2 has an action but no login, so that event is ignored and u2 is omitted. The summary is:

{ "u1": { "sessions": 1, "active_time": 150 } }

Practice input and output

In the coding workspace, the event objects are represented by three parallel arrays. At index i, users[i] is user, timestamps[i] is ts, and types[i] is type.

Return the summary mapping as rows of [user, sessionCount, activeTime]. Write the count and active time as decimal strings, and sort the rows by user ID in increasing lexicographic order. For the walkthrough above, return [["u1", "1", "150"]].

Function

buildSessions(users: String[], timestamps: int[], types: String[]) → String[][]

Examples

Example 1

users = ["u1","u1","u1","u1","u1","u1"]timestamps = [30,10,20,50,40,60]types = ["logout","login","action","login","action","logout"]return = [["u1","2","30"]]

After sorting, u1 has login 10, action 20, and logout 30, for active time 20. The action at 40 is ignored. Login 50 and logout 60 add 10. The result is 2 sessions and active time 30.

Example 2

users = ["u1","u1","u1","u1"]timestamps = [50,30,10,20]types = ["action","login","login","action"]return = [["u1","2","30"]]

Login 10 and action 20 form the first session, which the login at 30 closes at 20. The second session ends at its last action, 50. Their durations are 10 and 20, so the total is 30 across 2 sessions.

Example 3

users = ["u1","u2","u1"]timestamps = [5,10,20]types = ["action","login","logout"]return = [["u2","1","0"]]

Both u1 events occur without an open session and are ignored. The lone u2 login creates 1 session with active time 0.

Example 4

users = ["u1","u1","u1","u2"]timestamps = [100,250,180,120]types = ["login","logout","action","action"]return = [["u1","1","150"]]

This is the source example. Sorting u1's events gives login at 100, action at 180, then logout at 250. Its one session lasts 250 - 100 = 150. The u2 action at 120 occurs without a login and is ignored.

Constraints

  • For this exercise, assume 0 <= users.length <= 10000.
  • users.length = timestamps.length = types.length.
  • For this exercise, assume each user ID has 1 to 32 characters and contains only lowercase ASCII letters and digits.
  • For this exercise, assume -2147483648 <= timestamps[i] <= 2147483647.
  • Every event type is one of login, action, or logout.
  • Events for the same user have distinct timestamps. Different users may share timestamps.

More Scale AI problems

See Scale AI hiring insights
Saved
public String[][] buildSessions(String[] users, int[] timestamps, String[] types) {
    // write your code here
}
users["u1","u1","u1","u1","u1","u1"]
timestamps[30,10,20,50,40,60]
types["logout","login","action","login","action","logout"]
expected[["u1", "2", "30"]]
Checking account…