2016-05-07 106 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