From f2a1a74bb850c8059764db26ab82d3261eb4a30a Mon Sep 17 00:00:00 2001 From: kageru Date: Tue, 26 Nov 2019 13:01:29 +0100 Subject: [PATCH] Add more filters and heatmaps --- .../kotlin/moe/kageru/spektacles/Counter.kt | 26 ++++++++++++++ .../kotlin/moe/kageru/spektacles/Filters.kt | 23 ++++++++++++ .../kotlin/moe/kageru/spektacles/IoHandler.kt | 2 +- .../spektacles/{ParsedLine.kt => Parser.kt} | 16 ++++++--- .../moe/kageru/spektacles/Reductions.kt | 15 ++++++++ .../moe/kageru/spektacles/Spektacles.kt | 35 +++++++------------ 6 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 src/main/kotlin/moe/kageru/spektacles/Counter.kt create mode 100644 src/main/kotlin/moe/kageru/spektacles/Filters.kt rename src/main/kotlin/moe/kageru/spektacles/{ParsedLine.kt => Parser.kt} (84%) create mode 100644 src/main/kotlin/moe/kageru/spektacles/Reductions.kt diff --git a/src/main/kotlin/moe/kageru/spektacles/Counter.kt b/src/main/kotlin/moe/kageru/spektacles/Counter.kt new file mode 100644 index 0000000..833e980 --- /dev/null +++ b/src/main/kotlin/moe/kageru/spektacles/Counter.kt @@ -0,0 +1,26 @@ +package moe.kageru.spektacles + +open class Counter(source: Iterable) : Iterable> { + val counts: Map = mutableMapOf().apply { + for (element in source) { + this[element] = this.getOrDefault(element, 0) + 1 + } + } + + override fun iterator(): Iterator> { + return counts.entries.iterator() + } + + override fun toString(): String { + return counts.entries.joinToString("\n") { "${it.key}: ${it.value}" } + } +} + +class SortedCounter>(source: Iterable): Counter(source) { + override fun toString(): String { + return counts.entries.sortedBy { it.key }.joinToString("\n") { "${it.key}: ${it.value}" } + } +} + +fun Iterable.toCounter(): Counter = Counter(this) +fun > Iterable.toSortedCounter(): SortedCounter = SortedCounter(this) diff --git a/src/main/kotlin/moe/kageru/spektacles/Filters.kt b/src/main/kotlin/moe/kageru/spektacles/Filters.kt new file mode 100644 index 0000000..d8d42f7 --- /dev/null +++ b/src/main/kotlin/moe/kageru/spektacles/Filters.kt @@ -0,0 +1,23 @@ +package moe.kageru.spektacles + +import java.time.Month + +fun ParsedLines.filterUsers(vararg users: String): ParsedLines { + return this.filter { line -> line.user.exists { it in users } } +} + +fun ParsedLines.filterModes(vararg modes: UserMode): ParsedLines { + return this.filter { line -> line.userMode in modes } +} + +fun ParsedLines.filterYears(vararg years: Int): ParsedLines { + return this.filter { line -> line.time.year in years } +} + +fun ParsedLines.filterMonths(vararg months: Month): ParsedLines { + return this.filter { line -> line.time.month in months } +} + +fun ParsedLines.filterDays(vararg days: Int): ParsedLines { + return this.filter { line -> line.time.dayOfMonth in days } +} diff --git a/src/main/kotlin/moe/kageru/spektacles/IoHandler.kt b/src/main/kotlin/moe/kageru/spektacles/IoHandler.kt index 671cc92..7d3a94b 100644 --- a/src/main/kotlin/moe/kageru/spektacles/IoHandler.kt +++ b/src/main/kotlin/moe/kageru/spektacles/IoHandler.kt @@ -8,4 +8,4 @@ object IoHandler { .filter { !it.startsWith("****") } } -typealias Lines = Sequence \ No newline at end of file +typealias Lines = Sequence diff --git a/src/main/kotlin/moe/kageru/spektacles/ParsedLine.kt b/src/main/kotlin/moe/kageru/spektacles/Parser.kt similarity index 84% rename from src/main/kotlin/moe/kageru/spektacles/ParsedLine.kt rename to src/main/kotlin/moe/kageru/spektacles/Parser.kt index 2471a18..d469174 100644 --- a/src/main/kotlin/moe/kageru/spektacles/ParsedLine.kt +++ b/src/main/kotlin/moe/kageru/spektacles/Parser.kt @@ -6,7 +6,7 @@ import java.time.LocalDateTime class ParsedLine(val time: LocalDateTime, val user: Option, - val userMode: Option, + val userMode: UserMode, val message: String, val isSystemMessage: Boolean, private val originalMessage: String @@ -30,7 +30,7 @@ class ParsedLine(val time: LocalDateTime, it.groups["second"]!!.value.toInt() ), it.groups["author"]?.value.toOption(), - it.groups["mode"]?.value?.let { UserMode.values().first { mode -> mode.icon == it } }.toOption(), + it.groups["mode"]?.value?.let { UserMode.values().first { mode -> mode.icon == it } } ?: UserMode.NONE, it.groups["message"]!!.value, it.groups["author"] == null, it.value @@ -44,5 +44,13 @@ enum class UserMode(val icon: String) { BOT("&"), OP("@"), HOP("%"), - VOICE("+"); -} \ No newline at end of file + VOICE("+"), + NONE("") +} + +typealias ParsedLines = Sequence + +fun Lines.parse(): ParsedLines { + return map { ParsedLine.parse(it) } + .filterNotNull() +} diff --git a/src/main/kotlin/moe/kageru/spektacles/Reductions.kt b/src/main/kotlin/moe/kageru/spektacles/Reductions.kt new file mode 100644 index 0000000..5e52a0c --- /dev/null +++ b/src/main/kotlin/moe/kageru/spektacles/Reductions.kt @@ -0,0 +1,15 @@ +package moe.kageru.spektacles + +import java.time.Month + +fun ParsedLines.heatMapByHour(): SortedCounter = heatMapBy { it.time.hour } + +fun ParsedLines.heatMapByMinute(): SortedCounter = heatMapBy { it.time.hour * 100 + it.time.minute } + +fun ParsedLines.heatMapByMonth(): SortedCounter = heatMapBy { it.time.month } + +private fun >ParsedLines.heatMapBy(op: (ParsedLine) -> T): SortedCounter { + return this.map(op) + .asIterable() + .toSortedCounter() +} diff --git a/src/main/kotlin/moe/kageru/spektacles/Spektacles.kt b/src/main/kotlin/moe/kageru/spektacles/Spektacles.kt index 8df69fd..09dbb49 100644 --- a/src/main/kotlin/moe/kageru/spektacles/Spektacles.kt +++ b/src/main/kotlin/moe/kageru/spektacles/Spektacles.kt @@ -1,32 +1,21 @@ package moe.kageru.spektacles +import java.time.Month import kotlin.system.measureTimeMillis - fun main() { - val res = measureTimeMillis { - IoHandler.readFile("test.log") - .map { ParsedLine.parse(it) } - .filterNotNull() - .filter { line -> line.user.exists { it == "kageru_" } } - .flatMap { it.message.split(' ').asSequence() } - //.flatMap { it.message.split(' ').k() } - //.toCounter() - //.counts["selphyDango"] + val time = measureTimeMillis { + spektacle() } - println(res) + println("Time spent: $time ms") } -class Counter(source: Iterable) : Iterable { - val counts = mutableMapOf().apply { - for (element in source) { - this[element] = this.getOrDefault(element, 0) + 1 - } - } - - override fun iterator(): Iterator { - return counts.keys.iterator() - } +fun spektacle() { + IoHandler.readFile("test.log") + .parse() + .filterUsers("kageru_") + .filterModes(UserMode.OP) + .filterMonths(Month.APRIL) + .heatMapByHour() + .let(::println) } - -fun Iterable.toCounter(): Counter = Counter(this)