簡體   English   中英

如何以正確的Scala功能方式編寫以下代碼段?

[英]How to write the following snippet in a correct Scala functional way?

我是Scala的新手,想知道這是否是正確的書寫方式:

def createCol(prior: List[Int], current: List[Int]): List[Int] = {
  if (prior.isEmpty) List(1) ++ current
  else if (prior.tail.isEmpty)   // begin of the block to improve
    createCol(prior.tail, current ++ List(prior.head))
  else
    createCol(prior.tail, current ++ List(prior.head + prior.tail.head))
}

我感興趣的部分是:

if (prior.tail.isEmpty)
  createCol(prior.tail, current ++ List(prior.head))
else
  createCol(prior.tail, current ++ List(prior.head + prior.tail.head))

由於我要重復幾乎相同的函數調用createCol因此我嘗試了以下方法:

val ssum = if (prior.tail.isEmpty) prior.head else prior.head + prior.tail.head
createCol(prior.tail, current ++ List(ssum))

最好或推薦的方法是什么?

謝謝

幾點:

  1. 我將您的功能更改為使用Scala的模式匹配框架,因為它極大地簡化了您的代碼。

  2. 您不應該執行List(x) ++ someList因為這樣會不必要地構造單項列表。 您應該只使用prepend方法:: :(或+: :)。 追加( :+ )也一樣。

  3. 如果prior只有一個元素,則您將要進行的所有遞歸調用都將1放在current的前面。 因此,您可以從第二種情況中刪除遞歸調用。

  4. 您的方法是尾遞歸的,因此請使用@tailrec對其進行@tailrec

  5. 最后,考慮使用Vector而不是List 追加到List是O(n),因為該方法必須一直遍歷到底(然后從后到前重建列表)。 但是,在Vector前面和后面都有效地是O(1)。

所以:

@tailrec
def createCol(prior: List[Int], current: List[Int]): List[Int] = {
  prior match {
    case Nil => 1 :: current
    case head :: Nil => 1 +: current :+ head
    case head :: tail => createCol(tail, current :+ (head + tail.head))
  }
}

您也可以在兩種情況下這樣做,就像您在問題中描述的那樣。 但是您應該使用headOption方法,而不是顯式地執行if/else

@tailrec
def createCol(prior: List[Int], current: List[Int]): List[Int] = {
  prior match {
    case Nil =>
      1 :: current
    case head :: tail =>
      createCol(tail, current ++ List(head + tail.headOption.getOrElse(0)))
  }
}

您的功能似乎等同於以下內容:

def createCol(prior: List[Int], current: List[Int]) =
  if (prior.isEmpty) 1 :: current
  else 1 :: current ::: (prior, prior.tail :+ 0).zipped.map(_ + _)

或使用Vector ,如果列表很長,則應該在添加和添加時表現出更好的性能:

def createCol(prior: Vector[Int], current: Vector[Int]) =
  if (prior.isEmpty) 1 +: current
  else (1 +: current) ++ (prior, prior.tail :+ 0).zipped.map(_ + _)

這樣可以避免遞歸,而且我認為可以很清楚地看到未修改current ,無論如何都只是添加1 ,並且prior自身與最后一個元素的偏移量為1(與0求和),然后附加到current上。

甚至避免重復(1 +:current):

(1 +: current) ++ (
  if (prior.isEmpty) Vector()
  else (prior, prior.tail :+ 0).zipped.map(_ + _))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM