collection 内的模式匹配
Patttern matching within collection
我想在 Seq 中寻找特定的模式。我尝试同时使用 :+ 和 +: 运算符,但即使编译它似乎也不起作用,现在我必须首先依赖 'dropwhile' 操作,然后在collection.
在 Scala 中不可能写出类似的东西吗? 'from' 和 'to' 是现有变量
case beginColl :+ `from` +: someElement +: `to` +: tail => true
编辑:它是 objects 的序列,而不是列表
我认为您可能需要识别这样的序列:
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
}
这应该有效:
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
}
您可以使用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.
这在该定义中永远不会起作用,因为您不能在 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
至少包含三个元素,其中第一个和第三个是 from
和 to
我想在 Seq 中寻找特定的模式。我尝试同时使用 :+ 和 +: 运算符,但即使编译它似乎也不起作用,现在我必须首先依赖 'dropwhile' 操作,然后在collection.
在 Scala 中不可能写出类似的东西吗? 'from' 和 'to' 是现有变量
case beginColl :+ `from` +: someElement +: `to` +: tail => true
编辑:它是 objects 的序列,而不是列表
我认为您可能需要识别这样的序列:
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
}
这应该有效:
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
}
您可以使用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.
这在该定义中永远不会起作用,因为您不能在 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
至少包含三个元素,其中第一个和第三个是 from
和 to