【问题标题】:Pattern matching list prefixes in ScalaScala中的模式匹配列表前缀
【发布时间】:2015-07-29 06:44:52
【问题描述】:

我对列表前缀(即列表的前几个元素)的模式匹配有疑问。

这可以编译,但没有按预期工作:

  val l = List(1,2,3)

  val test = { m: List[Int] =>
    m match {
      case l :: tail => println("tail: "+tail.mkString(","))
      case _ => println("no match")
    }
  }

  test(List(1,2,3,4,5))

输出为tail: 2,3,4,5。我希望它会说tail: 4,5,或者不匹配,或者在编译时失败。是什么让它如此运作?

我的第二个问题是:如何使用列表匹配列表前缀?我知道这可以按我的预期工作:

      case 1 :: 2 :: 3 :: tail => println("tail: "+tail.mkString(","))

但是,我的前缀是列表,不能硬编码。模式匹配在这里是否正确?

我知道我可以做类似的事情

    if (m startsWith l) {
      val tail = m drop l.size          
    }

但一长串这些似乎相当不雅,尤其是在 Scala 中。

【问题讨论】:

  • 如果前缀List(1,2,6)List(1,2,3,4,5) 匹配,您的预期结果是什么?是List(3,4,5)还是不匹配?
  • 好点。我希望没有匹配。
  • 两个评价最高的答案都很棒 - StackOverflow 需要共同接受!

标签: list scala pattern-matching


【解决方案1】:

我认为这是不可能的。基于此解决方法我可以提出的最接近的语法:

import collection.SeqLike

implicit class PrefixMatcher[T](prefix: Seq[T]) {
  object then  {
    def unapply[S <: SeqLike[T,S]](seq: S): Option[S] =
      if (seq startsWith prefix) Some(seq drop prefix.length) else None
  }
}

那么你可以把它当作

val test: List[Int] => Unit = {
  case l.then(tail) => println("tail: " + tail.mkString(","))
  case _ => println("no match")
}

【讨论】:

    【解决方案2】:

    关于您的第一个代码 sn-p 的输出,match 内部的 l 实际上是一个新值,它隐藏了外部作用域 l 并在执行期间捕获 1

    您遇到的问题是::Listunapply,将其分解为一个head 值和tail,解构链表。

    虽然有一个::: 操作与::: 一起用于连接两个列表,但它没有相应的unapply 可以让您以您想要的方式在模式匹配中使用它。

    【讨论】:

    • +1 实际解决了我关于 l 匹配的问题 - 我有点尴尬,我自己没有意识到这一点。
    【解决方案3】:

    解决您问题的第一部分:正如@Arne 提到的,case l 没有与您的列表匹配,而是捕获了一个新列表。对于前者,您需要将其括在反引号中,但即使那样我也看不出您如何实现您想要的,我能想到的关闭是:

     case `l` :+ x => println(s"tail is $s") //but this just works when the tail is just one element long. 
    

    对于你问题的最后一部分,也许模式匹配在这里不是正确的做法,怎么样:

     val prefixes = List (List (1,2,3), List(4,5,6)...)
    
     def findTail(li:List[Int]) =  prefixes.collectFirst{ case p if li.startsWith(p) => li.drop(p.size) } //Option[List[Int]] 
    

    如果没有匹配,这将找到与testListNone 匹配的第一个前缀的尾部。您可以轻松地将其概括为与Ints 以外的其他对象一起使用。

    【讨论】:

      猜你喜欢
      • 2018-10-01
      • 2012-10-14
      • 2017-10-14
      • 2015-05-30
      • 2015-01-17
      • 1970-01-01
      • 2015-07-27
      • 1970-01-01
      • 2015-04-27
      相关资源
      最近更新 更多