Cleaner logic for implicit values and aggregating

This commit is contained in:
Guntis Smaukstelis
2023-04-26 17:27:15 +03:00
parent 1bf41973a7
commit 81d07eb096
2 changed files with 50 additions and 58 deletions
+14 -16
View File
@@ -28,23 +28,21 @@ object AggregateValue {
case class precipitationList(value: Map[LocalDateTime, Double]) extends AggregateValue case class precipitationList(value: Map[LocalDateTime, Double]) extends AggregateValue
private def encodeDateTimeMap(map: Map[LocalDateTime, Double]): Json = {
map.map { case (dateTime, value) =>
Json.obj(dateFormatter.format(dateTime) -> Json.fromDoubleOrNull(value))
}.toList.asJson
}
implicit val encodeAggregateValue: Encoder[AggregateValue] = Encoder.instance { implicit val encodeAggregateValue: Encoder[AggregateValue] = Encoder.instance {
case tm: tempMax => Json.fromDoubleOrNull(tm.value) case key: tempMax => Json.fromDoubleOrNull(key.value)
case tml: tempMaxList => tml.value.map { case (dateTime, value) => case key: tempMaxList => encodeDateTimeMap(key.value)
Json.obj(dateFormatter.format(dateTime) -> Json.fromDoubleOrNull(value)) case key: tempMin => Json.fromDoubleOrNull(key.value)
}.toList.asJson case key: tempMinList => encodeDateTimeMap(key.value)
case tmin: tempMin => Json.fromDoubleOrNull(tmin.value) case key: tempAvg => Json.fromDoubleOrNull(key.value)
case tml: tempMinList => tml.value.map { case (dateTime, value) => case key: tempAvgList => encodeDateTimeMap(key.value)
Json.obj(dateFormatter.format(dateTime) -> Json.fromDoubleOrNull(value)) case key: precipitationSum => Json.fromDoubleOrNull(key.value)
}.toList.asJson case key: precipitationList => encodeDateTimeMap(key.value)
case tavg: tempAvg => Json.fromDoubleOrNull(tavg.value)
case tml: tempAvgList => tml.value.map { case (dateTime, value) =>
Json.obj(dateFormatter.format(dateTime) -> Json.fromDoubleOrNull(value))
}.toList.asJson
case psum: precipitationSum => Json.fromDoubleOrNull(psum.value)
case plist: precipitationList => plist.value.map { case (dateTime, value) =>
Json.obj(dateFormatter.format(dateTime) -> Json.fromDoubleOrNull(value))
}.toList.asJson
} }
def getKeys: List[String] = { def getKeys: List[String] = {
+36 -42
View File
@@ -33,7 +33,7 @@ object Parser {
} yield WeatherStationData(city, timestamp, meteoData, phenomena) } yield WeatherStationData(city, timestamp, meteoData, phenomena)
} }
private def aggregateLines( def queryData(
lines: List[String], lines: List[String],
cities: List[String], cities: List[String],
aggregator: AggregateKey, aggregator: AggregateKey,
@@ -43,48 +43,42 @@ object Parser {
.filter(line => cities.contains(line.city)) .filter(line => cities.contains(line.city))
.groupBy(_.city) .groupBy(_.city)
aggregator match { def aggregateValue(
case AggregateKey.tempMax => weatherByCity.map { case (city, weatherData) => city -> selector: MeteoData => Option[Double],
AggregateValue.tempMax(weatherData.flatMap(_.meteo.tempMax).max) } aggregate: List[Double] => Double,
case AggregateKey.tempMaxList => weatherByCity.map { case (city, weatherData) => city -> constructor: Double => AggregateValue
AggregateValue.tempMaxList(weatherData.collect { ): Map[String, AggregateValue] = {
case wd if wd.meteo.tempMax.isDefined => wd.timestamp -> wd.meteo.tempMax.get weatherByCity.map { case (city, weatherData) =>
}.toMap) } val values = weatherData.flatMap(wd => selector(wd.meteo))
city -> constructor(aggregate(values))
case AggregateKey.tempMin => weatherByCity.map { case (city, weatherData) => city ->
AggregateValue.tempMin(weatherData.flatMap(_.meteo.tempMin).min) }
case AggregateKey.tempMinList => weatherByCity.map { case (city, weatherData) => city ->
AggregateValue.tempMinList(weatherData.collect {
case wd if wd.meteo.tempMin.isDefined => wd.timestamp -> wd.meteo.tempMin.get
}.toMap)}
case AggregateKey.tempAvg => weatherByCity.map { case (city, weatherData) => city ->
AggregateValue.tempAvg({
val avgList = weatherData.flatMap(_.meteo.tempAvg)
avgList.sum / avgList.length
})}
case AggregateKey.tempAvgList => weatherByCity.map { case (city, weatherData) => city ->
AggregateValue.tempAvgList(weatherData.collect {
case wd if wd.meteo.tempAvg.isDefined => wd.timestamp -> wd.meteo.tempAvg.get
}.toMap)}
case AggregateKey.precipitationSum => weatherByCity.map { case (city, weatherData) => city ->
AggregateValue.precipitationSum(weatherData.flatMap(_.meteo.precipitation).sum)}
case AggregateKey.precipitationList => weatherByCity.map { case (city, weatherData) => city ->
AggregateValue.precipitationList(weatherData.collect {
case wd if wd.meteo.precipitation.isDefined => wd.timestamp -> wd.meteo.precipitation.get
}.toMap)
} }
// TODO add here other aggregateParams }
def aggregateList(
selector: WeatherStationData => Option[(LocalDateTime, Double)],
constructor: Map[LocalDateTime, Double] => AggregateValue
): Map[String, AggregateValue] = {
weatherByCity.map { case (city, weatherData) =>
val values = weatherData.flatMap(selector).toMap
city -> constructor(values)
}
}
val AggKey = AggregateKey
val AggVal = AggregateValue
aggregator match {
case AggKey.tempMax => aggregateValue(_.tempMax, _.max, AggVal.tempMax)
case AggKey.tempMaxList => aggregateList(wd => wd.meteo.tempMax.map(wd.timestamp -> _), AggVal.tempMaxList)
case AggKey.tempMin => aggregateValue(_.tempMin, _.min, AggVal.tempMin)
case AggKey.tempMinList => aggregateList(wd => wd.meteo.tempMin.map(wd.timestamp -> _), AggVal.tempMinList)
case AggKey.tempAvg => aggregateValue(_.tempAvg, values => values.sum / values.length, AggVal.tempAvg)
case AggKey.tempAvgList => aggregateList(wd => wd.meteo.tempAvg.map(wd.timestamp -> _), AggVal.tempAvgList)
case AggKey.precipitationSum => aggregateValue(_.precipitation, _.sum, AggVal.precipitationSum)
case AggKey.precipitationList => aggregateList(wd => wd.meteo.precipitation.map(wd.timestamp -> _), AggVal.precipitationList)
} }
} }
// TODO move out
def queryData(
data: List[String],
cities: List[String],
aggregator: AggregateKey,
): Map[String, AggregateValue] = {
aggregateLines(data, cities, aggregator)
}
} }