Solution: Crime analysis

The problem is that the readLines function reads all lines from the file and stores them in memory. The solution is to use the useLines function, which reads lines from a file lazily.

The following solution uses the groupBy function to group elements, and it uses the useLines function to read lines from the file:

fun main() { measureTimeMillis { File("Crimes_-_2001_to_Present.csv") .useLines { lines -> lines.drop(1) .map { Crime.parse(it) } .groupBy { it.primaryType } .mapValues { it.value.size } .toList() .sortedByDescending { (_, num) -> num } .joinToString(separator = "\n") { (type, num) -> "$num $type" } .let(::println) } }.let { println("Took $it") } }

The following solution uses the groupingBy function to group elements, and it uses the useLines function to read lines from the file:

fun main() { measureTimeMillis { File("Crimes_-_2001_to_Present.csv") .useLines { lines -> lines.drop(1) .map { Crime.parse(it) } .groupingBy { it.primaryType } .eachCount() .toList() .sortedByDescending { (_, num) -> num } .joinToString(separator = "\n") { (type, num) -> "$num $type" } .let(::println) } }.let { println("Took $it") } }

On my machine (MacBook Pro M2, data from late 2023), this is what the execution time looks like:

  • 6707 ms when using groupBy.
  • 4455 ms when using groupingBy.