2013-10-28 46 views
3

我試圖解決這個問題的S-99: Ninety-Nine Scala Problems斯卡拉 - 圖案匹配和For循環問題

鑑於在問題P10指定生成的行程長度代碼表12, 構建其未壓縮版本。例如:

scala> decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))) 
res0: List[Symbol] = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e) 

我試圖圖案元素在列表中匹配,然後用一個for循環來串聯字符,但我已經有了5號線以下編譯錯誤:

type mismatch; found : scala.collection.immutable.IndexedSeq[List[A]] required: List[A] 

1 def decode[A](xs: List[(Int, A)]) : List[A] = xs match { 
2  case Nil => Nil 
3  case x :: xs => { 
4     for { 
5      i <- 1 to x._1 
6     } yield (x._2) :: decode(xs) 
7     } 
8 } 

對不起,但我開始Scala。有人可以解釋爲什麼會發生這種情況,以及如何解決它?

回答

4

你相當接近 - 只是一些問題。這是我想出的一個固定版本:

def decode[A](xs: List[(Int, A)]) : List[A] = xs match { 
    case Nil => Nil 
    case x :: xs => (for { 
         i <- 1 to x._1 
        } yield (x._2)).toList ::: decode(xs) 
} 

第一個 - 也許是最重要的 - 就是for-yield周圍的額外括號。沒有這個,你試圖產生(x._2) :: decode(xs),而不僅僅是(x._2)(爲了彌補這一點,圍繞整個情況的{}可以省略)。

接下來,for-yield會導致IndexedSeq而不是List,所以我強制轉換爲List(您可以用各種方式處理這個,這只是最方便的)。

最後,串聯從decode(xs)產生的名單需要:::運營商(你也可以使用++),而不是::(其中前添加一個條目,而不是一個子列表)。

+0

[又一版本](https://gist.github.com/lazyval/bf0208414becf2e4e1ec)(因爲github在代碼格式化的註釋中做了很多不好的事情) –

+0

感謝您的回答=) – user2336315

4

主要問題是您用於連接列表的操作符 - ::僅用於將單個元素預先添加到列表中,因此在您的代碼中,您試圖預留yield(它本身就是一個序列)的結果,到List[A],並因此導致類型不兼容。這是一個可以工作的修改版本 - 它使用運算符++:,它可以用來將兩個序列連接在一起。我還將yield移到了一個單獨的語句中,否則您需要在收益率周圍使用括號,以便++:適用於yield的完整結果,而不是每個元素(由於類型不匹配而不再編譯)。

def decode[A](xs: List[(Int, A)]) : List[A] = xs match { 
    case Nil => Nil 
    case x :: xs => { 
    val repeatedElems = for { 
     i <- 1 to x._1 
    } yield (x._2) 
    repeatedElems ++: decode(xs) 
    } 
} 
+1

感謝您的回答! =)我只能接受一個答案,所以我會upvote你的,而不是=) – user2336315

+1

@ user2336315你也可以upvote那一個;-) –

2

其他的答案是完全沒有問題,但我認爲與List.fill生成解碼錶需要更少的語法和更容易比for-yield表達理解。

def decode[A](xs: List[(Int, A)]) : List[A] = xs match { 
    case Nil => Nil 
    case x :: xs => List.fill(x._1)(x._2) ::: decode(xs) 
} 

輸出:

scala> decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))) 
res0: List[Symbol] = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e) 
0

這裏是布萊恩的回答稍微修改後的版本。分解所述元組使代碼更加可讀:

def decode[A](xs: List[(Int, A)]) : List[A] = xs match { 
    case Nil => Nil 
    case (count, letter) :: xs => List.fill(count)(letter) ::: decode(xs) 
} 
0

的另一種方法是使用圖:

def decode[A](l: List[(Int, A)]): List[A] = { 
    val l1: List[List[A]] = l map { e => 
    List.fill(e._1)(e._2) 
    } 
    l1.flatten 
} 
+0

flatMap將更易讀(根本沒有中間變量) –