Paul Nogas
Paul Nogas

Reputation: 339

How to only map some items from a sequence and ignore others

I'm working on a tool to help me look through log files and decided to learn Kotlin at the same time. (I'm pretty new to the language so I apologize if this question is obvious.) For now I want to read a log file and compare each line to several regular expressions. Depending on which one it matches, I want to give a different color. I return these in a list for the UI to handle displaying them

Here are the problems I see with my current code:

  1. each line is being checked against the regular expression twice. This is an unnecessary performance hit which I want to avoid since this will eventually be handling VERY large log files
  2. I need to return something in the else statement to keep my type List<LineAndStyle> instead of becoming List<Any>.
fun process(file: File): List<LineAndStyle> {
    val result = file.useLines {
      it.filter { line ->
        exceptionsPattern.containsMatchIn(line) ||
          networkPattern.containsMatchIn(line) ||
          dataPattern.containsMatchIn(line)
      }.map { line ->
        when {
          exceptionsPattern.containsMatchIn(line) -> LineAndStyle(line, Color.PINK)
          networkPattern.containsMatchIn(line) -> LineAndStyle(line, Color.LIGHTBLUE)
          dataPattern.containsMatchIn(line) -> LineAndStyle(line, Color.LIGHTGREEN)
          else -> {
            LineAndStyle(line, Color.BLACK)
          }
        }
      }.toList()
    }
    return result
}

Please help me understand the idiomatic way to do this in Kotlin.

Upvotes: 1

Views: 337

Answers (1)

Andrei Tanana
Andrei Tanana

Reputation: 8432

How about this?

fun process(file: File): List<LineAndStyle> =
    file.useLines { lines ->
        lines.mapNotNull { line ->
            when {
                exceptionsPattern.containsMatchIn(line) -> LineAndStyle(line, Color.PINK)
                networkPattern.containsMatchIn(line) -> LineAndStyle(line, Color.LIGHTBLUE)
                dataPattern.containsMatchIn(line) -> LineAndStyle(line, Color.LIGHTGREEN)
                else -> null
            }
        }.toList()
    }

Upvotes: 2

Related Questions