簡體   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