匹配scala中序列中的序列

时间:2014-11-30 20:03:41

标签: scala pattern-matching

我希望匹配序列中的序列,如ex 1或ex 2;

List(1, 2, 3, 4) match {
  case 1 :: List(_*) :: 4 :: tail => // Ex 1
  case 1 :: (seq : List[Int]) :: 4 :: tail => // Ex 2
  case _ => 
}

这是fixed length sequence pattern _*的变体。与_*一样,我并不关心内部模式的内容,但重要的是长度可以变化,模式被前缀包围(例如1以上)和后缀(如4)。

我的问题是,如果您有任何诡计通过一些狡猾的unapply魔法做到这一点,或者您只是迭代列表以手动搜索序列。

提前致谢! : - )

2 个答案:

答案 0 :(得分:2)

这实际上超出了应该使用模式匹配的范围。即使您可以使用一组自定义unapply方法来执行您想要的操作,但是匹配是否贪婪等等也不会显而易见。

但是,如果您真的想要,可以按照以下步骤(例如):

import scala.collection.SeqLike
class Decon[A](a0: A, a1: A) {
  def unapply[C <: SeqLike[A, C]](xs: C with SeqLike[A, C]): Option[(C, C)] = {
     xs.span(_ != a1) match {
       case (a0 +: pre, a1 +: post) => Some((pre,post))
       case _ => None
     }
   }
}
val Dc = new Decon(1,4)

scala> List(1,2,3,4,5) match { case Dc(pre, post) => (pre, post); case _ => (Nil, Nil) }
res1: (List[Int], List[Int]) = (List(2, 3),List(5))

必须将匹配的固定元素14的规范分开;否则,正常算法会要求unapply返回值而不知道正在寻找什么,然后测试以确保它们是正确的。

答案 1 :(得分:1)

你可以这样做:

List(1,2,3,4) match {
    case 1 :: tail if tail.last == 4 => println("Found it!")
  }

但是,如果您在last中检查LinearSeqOptimized的实施情况:

  def last: A = {
    if (isEmpty) throw new NoSuchElementException
    var these = this
    var nx = these.tail
    while (!nx.isEmpty) {
      these = nx
      nx = nx.tail
    }
    these.head
  }

确实在迭代。这是因为List继承自LinearSeq,其经过优化可提供高效的headtail操作。对于您想要执行的操作,最好使用IndexedSeq实施,例如Vector具有优化length操作,在last中使用:

override /*TraversableLike*/ def last: A = {
    if (isEmpty) throw new UnsupportedOperationException("empty.last")
    apply(length-1)
  }

所以你可以这样做:

Vector(1,2,3,4) match {
    case v if v.head == 1 && v.last == 4 => println("Found it!")
  }