繁体   English   中英

scala 中函数式编程的性能

[英]Performance around functional programming in scala

我正在使用下面的东西来学习函数式编程和 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可以是OnOff ,如Status中所述。 我的输入是一系列命令,要求TurnOnTurnOffToggle从一个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 来描述整个矩阵的结束状态。 这可行,但对我来说似乎功能较少,因为我使用的是可变的 Map 而不是不可变的 object,所以我尝试将其重新考虑为更实用的方式,我最终得到了这个:

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)
      }
  }
})

关于这个过程,我有几个问题:

  1. 我的第二个版本在我看来不像第一个版本那样干净和直接,我不确定这是因为我对函数式编程不太熟悉还是我只是写了糟糕的函数式代码。
  2. 有没有办法简化第二部分的语法? 尤其是(m, item) =>??? function 在foldLeft部分? (m, (point, operation)) =>??? 给我语法错误
  3. 第二段代码需要更长的时间才能运行,这让我有点惊讶,因为这两个代码本质上是在做同样的事情,因为我没有太多的 Java 背景,知道什么可能导致性能问题吗?

非常感谢!

从函数式编程的角度来看,您的代码受到以下事实的影响:...

  1. lightStatus Map “保持状态”,因此需要突变。
  2. 状态变化的大“区域”==大量数据更新。

如果您可以接受每个灯状态作为Boolean值,那么这里的设计不需要突变并且即使在非常大的区域内也具有快速状态更新。

case class Point(x: Int, y:Int)

class LightGrid private (status: Point => Boolean) {
  def apply(p: Point): Boolean = status(p)

  private def isWithin(p:Point, ll:Point, ur:Point) =
    ll.x <= p.x && ll.y <= p.y && p.x <= ur.x && p.y <= ur.y

  //each light op returns a new LightGrid
  def turnOn(lowerLeft: Point, upperRight: Point): LightGrid =
    new LightGrid(point =>
      isWithin(point, lowerLeft, upperRight) || status(point))

  def turnOff(lowerLeft: Point, upperRight: Point): LightGrid =
    new LightGrid(point =>
      !isWithin(point, lowerLeft, upperRight) && status(point))

  def toggle(lowerLeft: Point, upperRight: Point): LightGrid =
    new LightGrid(point =>
      isWithin(point, lowerLeft, upperRight) ^ status(point))
}
object LightGrid {  //the public constructor
  def apply(): LightGrid = new LightGrid(_ => false)
}

用法:

val ON  = true
val OFF = false
val lg = LightGrid().turnOn(Point(2,2), Point(11,11)) //easy numbers
                    .turnOff(Point(8,8), Point(10,10))
                    .toggle(Point(1,1), Point(9,9))
lg(Point(1,1))    //ON
lg(Point(7,7))    //OFF
lg(Point(8,8))    //ON
lg(Point(9,9))    //ON
lg(Point(10,10))  //OFF
lg(Point(11,11))  //ON
lg(Point(12,12))  //OFF

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM