Add more filters and heatmaps
This commit is contained in:
parent
cd6bd4b488
commit
f2a1a74bb8
|
@ -0,0 +1,26 @@
|
||||||
|
package moe.kageru.spektacles
|
||||||
|
|
||||||
|
open class Counter<T>(source: Iterable<T>) : Iterable<Map.Entry<T, Int>> {
|
||||||
|
val counts: Map<T, Int> = mutableMapOf<T, Int>().apply {
|
||||||
|
for (element in source) {
|
||||||
|
this[element] = this.getOrDefault(element, 0) + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterator(): Iterator<Map.Entry<T, Int>> {
|
||||||
|
return counts.entries.iterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return counts.entries.joinToString("\n") { "${it.key}: ${it.value}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SortedCounter<T: Comparable<T>>(source: Iterable<T>): Counter<T>(source) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return counts.entries.sortedBy { it.key }.joinToString("\n") { "${it.key}: ${it.value}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Iterable<T>.toCounter(): Counter<T> = Counter(this)
|
||||||
|
fun <T: Comparable<T>> Iterable<T>.toSortedCounter(): SortedCounter<T> = SortedCounter(this)
|
|
@ -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 }
|
||||||
|
}
|
|
@ -8,4 +8,4 @@ object IoHandler {
|
||||||
.filter { !it.startsWith("****") }
|
.filter { !it.startsWith("****") }
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias Lines = Sequence<String>
|
typealias Lines = Sequence<String>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import java.time.LocalDateTime
|
||||||
|
|
||||||
class ParsedLine(val time: LocalDateTime,
|
class ParsedLine(val time: LocalDateTime,
|
||||||
val user: Option<String>,
|
val user: Option<String>,
|
||||||
val userMode: Option<UserMode>,
|
val userMode: UserMode,
|
||||||
val message: String,
|
val message: String,
|
||||||
val isSystemMessage: Boolean,
|
val isSystemMessage: Boolean,
|
||||||
private val originalMessage: String
|
private val originalMessage: String
|
||||||
|
@ -30,7 +30,7 @@ class ParsedLine(val time: LocalDateTime,
|
||||||
it.groups["second"]!!.value.toInt()
|
it.groups["second"]!!.value.toInt()
|
||||||
),
|
),
|
||||||
it.groups["author"]?.value.toOption(),
|
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["message"]!!.value,
|
||||||
it.groups["author"] == null,
|
it.groups["author"] == null,
|
||||||
it.value
|
it.value
|
||||||
|
@ -44,5 +44,13 @@ enum class UserMode(val icon: String) {
|
||||||
BOT("&"),
|
BOT("&"),
|
||||||
OP("@"),
|
OP("@"),
|
||||||
HOP("%"),
|
HOP("%"),
|
||||||
VOICE("+");
|
VOICE("+"),
|
||||||
}
|
NONE("")
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias ParsedLines = Sequence<ParsedLine>
|
||||||
|
|
||||||
|
fun Lines.parse(): ParsedLines {
|
||||||
|
return map { ParsedLine.parse(it) }
|
||||||
|
.filterNotNull()
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package moe.kageru.spektacles
|
||||||
|
|
||||||
|
import java.time.Month
|
||||||
|
|
||||||
|
fun ParsedLines.heatMapByHour(): SortedCounter<Int> = heatMapBy { it.time.hour }
|
||||||
|
|
||||||
|
fun ParsedLines.heatMapByMinute(): SortedCounter<Int> = heatMapBy { it.time.hour * 100 + it.time.minute }
|
||||||
|
|
||||||
|
fun ParsedLines.heatMapByMonth(): SortedCounter<Month> = heatMapBy { it.time.month }
|
||||||
|
|
||||||
|
private fun <T: Comparable<T>>ParsedLines.heatMapBy(op: (ParsedLine) -> T): SortedCounter<T> {
|
||||||
|
return this.map(op)
|
||||||
|
.asIterable()
|
||||||
|
.toSortedCounter()
|
||||||
|
}
|
|
@ -1,32 +1,21 @@
|
||||||
package moe.kageru.spektacles
|
package moe.kageru.spektacles
|
||||||
|
|
||||||
|
import java.time.Month
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val res = measureTimeMillis {
|
val time = measureTimeMillis {
|
||||||
IoHandler.readFile("test.log")
|
spektacle()
|
||||||
.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"]
|
|
||||||
}
|
}
|
||||||
println(res)
|
println("Time spent: $time ms")
|
||||||
}
|
}
|
||||||
|
|
||||||
class Counter<T>(source: Iterable<T>) : Iterable<T> {
|
fun spektacle() {
|
||||||
val counts = mutableMapOf<T, Int>().apply {
|
IoHandler.readFile("test.log")
|
||||||
for (element in source) {
|
.parse()
|
||||||
this[element] = this.getOrDefault(element, 0) + 1
|
.filterUsers("kageru_")
|
||||||
}
|
.filterModes(UserMode.OP)
|
||||||
}
|
.filterMonths(Month.APRIL)
|
||||||
|
.heatMapByHour()
|
||||||
override fun iterator(): Iterator<T> {
|
.let(::println)
|
||||||
return counts.keys.iterator()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> Iterable<T>.toCounter(): Counter<T> = Counter(this)
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user