集合

时间:2015-05-12 12:57:45

标签: scala pattern-matching

我想在Seq中寻找一个特定的模式。我试图在同一时间使用:+和+:运算符,但它似乎无法工作,即使它编译,现在我必须首先依赖'dropwhile'操作,然后在集合的开头模式匹配。

是不是可以在Scala中写出类似的内容? 'from'和'to'是现有变量

case beginColl :+ `from` +: someElement +: `to` +: tail => true 

编辑:它是一个对象的Seq,而不是一个列表

4 个答案:

答案 0 :(得分:1)

这将永远不会在该定义中起作用,因为除了unapplySeq的结果中的尾部之外,您不能通配任何子序列。 但是,让我建议一个解决方法。

让我们定义这个帮手:

object Span {
  class Spanner[T](pred: T => Boolean) {
    def unapply(seq: Seq[T]) = for {
      idx <- Some(seq.indexWhere(pred)) if idx >= 0
      (start, elem +: end) = seq.splitAt(idx)
    } yield (start, end)
  }
  def apply[T](pred: T => Boolean) = new Spanner(pred)
}

这允许我们定义更多有趣的匹配器,如此函数:

def splitter[T](from:T, to:T): PartialFunction[Seq[T], Seq[Seq[T]]] = {
  val From = Span[T](_ == from)
  val To = Span[T](_ == to)

  {
    case From(prefix, To(middle, postfix)) => Seq(prefix, middle, postfix)
  }
}

因此,如果我们专注于:

val mySplitter = splitter("from", "to").lift

我们可以得到适当的结果:

mySplitter(Seq("1", "2", "to", "3", "4", "from", "5", "6")) // None
mySplitter(Seq("1", "2", "from", "3", "4", "to", "5", "6")) // Some(List(List(1, 2), List(3, 4), List(5, 6))) 

让我们试着澄清编译器如何理解你的语法,让我们定义

def splitter2(from: AnyRef, to: AnyRef): PartialFunction[Seq[_], AnyRef] = {
  case beginColl :+ `from` +: someElement +: `to` +: tail => (beginColl, someElement, tail)
}
val mySplitter2 = splitter2("from", "to").lift

所以,如果我们尝试匹配

mySplitter2(Seq("1", "2", "from", "3", "4 ", "to", "5", "6"))

我们肯定会得到None

但如果我们尝试

mySplitter2(Seq("1", "2", Seq("from", "3", "to", "4", "5")))

我们突然得到Some(...)

所以编译器只是把你的表达式理解为_match元素为

beginColl :+ __last

然后将__last

匹配
`from` +: someElement +: `to` +: tail

基本上验证这是非空的Seq最后一个元素是 另一个Seq由至少三个元素组成,其中第一个和第三个元素是fromto

答案 1 :(得分:0)

我认为您可能需要识别这样的序列:

val test = Seq("x", "from", "y", "to", "z")

test match {
  case _ :: "from" :: _ :: "to" :: _ => true
  case _ => false
}

但是,由于您需要知道序列是否具有特定的特征,我会尝试这样做:

test match {
  case list if (list.indexOf("from") < list.indexOf("to")) => true
  case _ => false
}

答案 2 :(得分:0)

这应该有效:

case Seq(_, `from`, _, `to`, _*) => true

编辑:

如果'from'之前有更多元素,dropWhile是一个很好的解决方案,另一种方法(但效率较低)可能是:

def matchSeq[T](s: Seq[T]): Boolean = s match { 
    case Seq(_, `from`, _, `to`, _*) => true
    case Seq(a, b@_*) => matchSeq(b) 
    case _ => false 
}

答案 3 :(得分:0)

您可以使用containsSlice检查序列是否包含子序列,或者您可以比较要查找的元素的索引。即:

val test = Seq("x", "from", "y", "to", "z")
val test2 = Seq("u", "w", "x", "from", "y", "to", "z")

test match {
  case s if s.indexOf("to") - s.indexOf("from") == 2 => true
  case _ => false
} //true in both cases.