I'm trying to rewrite a function in a functional style. I know the function is bad. But how can I avoid the usage of the var field watermarkTime
?
The function sets day "1" for the rows with a continuous increasing timestamp. If the timestamp is lesser than the timestamp of the previous row, then set day "2".
case class Row(time: String, name: String, var day: Int)
val rows = List(new Row("09:18:52", "3_0711-082757_01001", 0),
new Row("09:23:18", "3_0711-082757_01002", 0),
new Row("09:33:43", "3_0711-082757_01004", 0),
new Row("10:20:00", "3_0711-082757_01011", 0),
new Row("05:03:38", "3_0711-082757_02001", 0), // set secound day
new Row("05:07:51", "3_0711-082757_02002", 0),
new Row("05:13:02", "3_0711-082757_02003", 0),
new Row("05:19:16", "3_0711-082757_02004", 0),
new Row("10:54:27", "3_0711-082757_02015", 0), // set first day
new Row("11:00:38", "3_0711-082757_02016", 0),
new Row("11:07:28", "3_0711-082757_02017", 0))
def setDayFP(rows: List[Row]): List[Row] = {
var watermarkTime = 0
for (row <- rows) {
val newTime = row.time.replaceAll(":","").toInt
if (watermarkTime < newTime) {
watermarkTime = newTime
row.day = 1
} else {
row.day = 2
}
}
return rows
}
Here is the result (sorted by day and name):
Row(09:18:52,3_0711-082757_01001,1)
Row(09:23:18,3_0711-082757_01002,1)
Row(09:33:43,3_0711-082757_01004,1)
Row(10:20:00,3_0711-082757_01011,1)
Row(10:54:27,3_0711-082757_02015,1)
Row(11:00:38,3_0711-082757_02016,1)
Row(11:07:28,3_0711-082757_02017,1)
Row(05:03:38,3_0711-082757_02001,2)
Row(05:07:51,3_0711-082757_02002,2)
Row(05:13:02,3_0711-082757_02003,2)
Row(05:19:16,3_0711-082757_02004,2)
I'm looking for a better solution. Thanks in advance!
The solution below
has an immutable list class and uses copying instead of field updates
uses foldLeft
instead of a loop
uses a tuple as the fold's aggregator to carry around the watermarkTime
However, I personally would stick with your for-loop and the var watermarkTime
, since the foldLeft
doesn't make it more readable. I would keep the day: Option[Int]
and the copying, though.
case class Row(time: String, name: String, day: Option[Int] = None)
val rows = List(new Row("09:18:52", "3_0711-082757_01001"),
new Row("09:23:18", "3_0711-082757_01002"),
new Row("09:33:43", "3_0711-082757_01004"),
new Row("10:20:00", "3_0711-082757_01011"),
new Row("05:03:38", "3_0711-082757_02001"),
new Row("05:07:51", "3_0711-082757_02002"),
new Row("05:13:02", "3_0711-082757_02003"),
new Row("05:19:16", "3_0711-082757_02004"),
new Row("10:54:27", "3_0711-082757_02015"),
new Row("11:00:38", "3_0711-082757_02016"),
new Row("11:07:28", "3_0711-082757_02017"))
def setDayFP(rows: List[Row]): List[Row] = {
rows.foldLeft((0, List[Row]()))
{case ((watermarkTime, resultRows), row) =>
val newTime = row.time.replaceAll(":","").toInt
val (newWatermarkTime, day) =
if (watermarkTime < newTime)
(newTime, 1)
else
(watermarkTime, 2)
(newWatermarkTime, row.copy(day = Some(day)) :: resultRows)
}._2.reverse
}
setDayFP(rows).foreach(println)