【发布时间】:2021-08-23 00:34:00
【问题描述】:
我正在使用以下东西作为学习函数式编程和 scala 的一种方式,我来自 python 背景。
case class Point(x: Int, y:Int)
object Operation extends Enumeration {
type Operation = Value
val TurnOn, TurnOff, Toggle = Value
}
object Status extends Enumeration {
type Status = Value
val On, Off = Value
}
val inputs: List[String]
def parseInputs(s: String): (Point, Point, Operation)
想法是我们有一个光矩阵(Point),每个Point 可以是On 或Off,如Status 中所述。
我的输入是一系列命令,询问TurnOn、TurnOff 或Toggle 从一个Point 到另一个Point 的所有灯(使用两个点定义的矩形区域是左下角和上角-右上角)。
我原来的解决方案是这样的:
type LightStatus = mutable.Map[Point, Status]
val lightStatus = mutable.Map[Point, Status]()
def updateStatus(p1: Point, p2: Point, op: Operation): Unit = {
(p1, p2) match {
case (Point(x1, y1), Point(x2, y2)) =>
for (x <- x1 to x2)
for (y <- y1 to y2) {
val p = Point(x, y)
val currentStatus = lightStatus.getOrElse(p, Off)
(op, currentStatus) match {
case (TurnOn, _) => lightStatus.update(p, On)
case (TurnOff, _) => lightStatus.update(p, Off)
case (Toggle, On) => lightStatus.update(p, Off)
case (Toggle, Off) => lightStatus.update(p, On)
}
}
}
}
for ((p1, p2, op) <- inputs.map(parseInputs)) {
updateStatus(p1, p2, op)
}
现在我有lightStatus 作为地图来描述整个矩阵的结束状态。这可行,但对我来说似乎功能较少,因为我使用的是可变 Map 而不是不可变对象,所以我尝试将其重新考虑为更实用的方式,我最终得到了这个:
inputs.flatMap(s => parseInputs(s) match {
case (Point(x1, y1), Point(x2, y2), op) =>
for (x <- x1 to x2;
y <- y1 to y2)
yield (Point(x, y), op)
}).foldLeft(Map[Point, Status]())((m, item) => {
item match {
case (p, op) =>
val currentStatus = m.getOrElse(p, Off)
(op, currentStatus) match {
case (TurnOn, _) => m.updated(p, On)
case (TurnOff, _) => m.updated(p, Off)
case (Toggle, On) => m.updated(p, Off)
case (Toggle, Off) => m.updated(p, On)
}
}
})
我有几个关于这个过程的问题:
- 在我看来,我的第二个版本不像第一个版本那样简洁明了,我不确定这是因为我对函数式编程不太熟悉,还是我只是编写了糟糕的函数式代码。
- 有没有办法简化第二部分的语法?尤其是
foldLeft部分中的(m, item) => ???函数?像(m, (point, operation)) => ???这样的东西给了我语法错误 - 第二段代码的运行时间要长得多,这让我有点吃惊,因为这两个代码本质上是在做同样的事情,因为我没有太多的 Java 背景,不知道是什么导致了性能问题?
非常感谢!
【问题讨论】:
标签: scala functional-programming immutability