Introduction

Welcome to our new coding practice lesson! We have an interesting problem in this unit that centers around data from a social networking app. The challenge involves processing logs from this app and extracting useful information from them. This task will leverage your skills in string manipulation, working with timestamps, and task subdivision. Let's get started!

Task Statement

Imagine a social networking application that allows users to form groups. Each group has a unique ID ranging from 1 up to n, the total number of groups. The app keeps track of when a group is created and deleted, logging all these actions in a string.

Your task is to create a Scala function named analyzeLogs. This function will take as input a string of logs and output a List[(Int, String)] representing the groups with the longest lifetime. Each tuple in the list contains two items: the group ID (as an Int) and the group's lifetime (as a string in the format "HH:MM." By 'lifetime,' we mean the duration from when the group was created until its deletion. If a group has been created and deleted multiple times, the lifetime is the total sum of those durations. If multiple groups have the same longest lifetime, the function should return all such groups in ascending order of their IDs.

For example, if we have a log string as follows:
"1 create 09:00, 2 create 10:00, 1 delete 12:00, 3 create 13:00, 2 delete 15:00, 3 delete 16:00",
the function will return: List((2, "05:00")).

Solution Building: Step 1

First, we need to handle timestamps and split the input string into individual log entries. In Scala, we can use the java.time.LocalTime class to represent times and the java.time.Duration class to represent durations. To split the input string into separate log entries, we can use the split method.

import java.time.LocalTime
import java.time.Duration

def analyzeLogs(logs: String): List[(Int, String)] = {
  val logList = logs.split(", ").toList  // Split the log string into individual log entries
}
Solution Building: Step 2

Next, we need to process each log entry. For each entry, we split it into its components: the group ID, the action (create or delete), and the time. In Scala, we can use the split method and pattern matching to extract these values.

import java.time.LocalTime
import java.time.Duration

def analyzeLogs(logs: String): List[(Int, String)] = {
  val logList = logs.split(", ").toList

  for (log <- logList) {
    val parts = log.split(" ")
    val groupId = parts(0)
    val action = parts(1)
    val time = parts(2)
    // Further processing will be done in the next steps
  }
  List() // Placeholder return
}
Solution Building: Step 3

Now that we can extract the group ID, action, and time from each log entry, we need to process these details. We convert the group ID to an integer and the time to a LocalTime object. We use two mutable maps: one to keep track of the creation time for each group and another to accumulate the total lifetime for each group. When a group is created, we record its creation time. When it is deleted, we calculate the duration and add it to the group's total lifetime.

import java.time.LocalTime
import java.time.Duration
import scala.collection.mutable

def analyzeLogs(logs: String): List[(Int, String)] = {
  val logList = logs.split(", ").toList
  val timeMap = mutable.Map[Int, LocalTime]()      // To record the creation time for each group
  val lifeMap = mutable.Map[Int, Duration]()       // To record the total lifetime for each group

  for (log <- logList) {
    val parts = log.split(" ")
    val groupId = parts(0).toInt
    val action = parts(1)
    val time = LocalTime.parse(parts(2))           // Parse the time string to LocalTime

    if (action == "create") {
      timeMap(groupId) = time                      // Record the creation time
    } else if (action == "delete") {
      if (timeMap.contains(groupId)) {
        val duration = Duration.between(timeMap(groupId), time)
        val prev = lifeMap.getOrElse(groupId, Duration.ZERO)
        lifeMap(groupId) = prev.plus(duration)     // Add the duration to the group's total lifetime
        timeMap.remove(groupId)
      }
    }
  }
  List() // Placeholder return
}
Solution Building: Step 4
Lesson Summary

Congratulations! You have successfully tackled a non-trivial log analysis problem and worked with timestamped data, a real-world data type in Scala. By using Scala's java.time library and mutable maps, you transformed raw strings into meaningful data. Real-life coding often involves accurately understanding, dissecting, and analyzing data, and this unit's lesson has given you practical experience in that regard. Now, let's apply these new learnings to more practice challenges. Off to the races you go!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal