2016-05-07 104 views
3

我只是想在scala上做一些工作,並試圖自己實現List.concat函數。這裏是可變模式匹配可變參數

def concat[A](lists : Traversable[A]*):List[A]={ 
    println("concat called") 
    lists match { 
     case Nil => Nil 
     case x :: Nil => (x :\ List.empty[A])((elem,list)=> elem::list) 
     case x:: xs => (x :\ concat(xs:_*))((elem,list)=> elem :: list) 
    } 
    } 

但是當我嘗試調用此方法像

concat(List(1,2,3),List(2,3,4),List(4,5,6),List(6,7,8)) 

我得到錯誤

Exception in thread "main" scala.MatchError: WrappedArray(List(1, 2, 3), List(2, 3, 4), List(4, 5, 6), List(6, 7, 8)) (of class scala.collection.mutable.WrappedArray$ofRef) 

有人可以解釋我做錯了什麼在這裏的代碼? 在此先感謝

回答

6

Varags是Seq,你可以匹配它像一個Seq,名單上不喜歡的。這裏有一個例子:

@ a(1, 2, 3) 
res1: Seq[Int] = Array(1, 2, 3) 
@ def a(x: Int*) = x match { 
        case Seq() => "empty" 
        case Seq(a) => s"single $a" 
        case Seq(a, as @ _*) => s"multiple: $a, $as" 
       } 
defined function a 
@ a(1, 2, 3, 4) 
res3: String = "multiple: 1, WrappedArray(2, 3, 4)" 
@ a(1, 2) 
res4: String = "multiple: 1, WrappedArray(2)" 
@ a(1) 
res5: String = "single 1" 

Nil和​​做這樣的一致通常意味着,你可以簡單地使用foldLeft,它做到了這一點。

def concat[A](lists: Traversable[A]*): List[A] = 
    lists.foldLeft(List.empty[A])(_ ++ _) 

,並注意上Nil和​​,其中xs可以Nil是匹配的,就足夠了。你的第二個case可以簡單地刪除。

只要看看那些:

case Nil => Nil 
case x :: Nil => (x :\ List.empty[A])(_ :: _) 
case x :: xs => (x :\ concat(xs:_*))(_ :: _) 

最後兩個是相同的。如果在第三種情況下xs == Nil然後代替concat(xs:_*),您將得到您的Nil,這與List.empty[A](如果類型被正確傳入)相同。

3

NilList

scala> Nil 
res11: scala.collection.immutable.Nil.type = List() 

然而,斯卡拉包裝所有可變參數的參數爲​​SeqWrappedArray器具Seq),這就是爲什麼你得到的MatchError。你可以重寫你的函數以下列方式:

scala> def concat[A](lists : Traversable[A]*):List[A]={ 
    |  lists match { 
    |  case Seq() => Nil 
    |  case x +: Seq() => (x :\ List.empty[A])((elem,list)=> elem::list) 
    |  case x +: xs => (x :\ concat(xs:_*))((elem,list)=> elem :: list) 
    |  } 
    | } 
concat: [A](lists: Traversable[A]*)List[A] 

scala> concat(List(1), List(2), List(3)) 
res9: List[Int] = List(1, 2, 3) 

你也可以使用flatMap簡化功能:

scala> def concat[A](lists: Traversable[A]*): List[A] = { 
    |  lists.flatMap(x => x).toList 
    | } 
concat: [A](lists: Traversable[A]*)List[A] 

scala> concat(List(1), List(2), List(3)) 
res16: List[Int] = List(1, 2, 3) 
+0

他能以及簡化它做'lists.toList.flatten'但這可能WASN這點在這裏:) –

+0

當然,這就是爲什麼我在後期提到它:) – soon

+1

'lists.flatMap(x => x)'=='lists.flatten' – Dima