Scala模式与集合匹配

Kev*_*ith 15 scala pattern-matching

以下不起作用.

object Foo {
    def union(s: Set[Int], t: Set[Int]): Set[Int] = t match {
        case isEmpty => s
        case (x:xs)  => union(s + x, xs)
        case _       => throw new Error("bad input")
    }
}
Run Code Online (Sandbox Code Playgroud)

错误:未找到:输入xs

如何在一组上进行模式匹配?

Dan*_*ral 19

嗯,类型的x:xs手段,所以它不会工作.但是,唉,你不能模式匹配集,因为集合没有定义的顺序.或者,更实际,因为没有提取器.xxsSet

您可以随时定义自己的:

object SetExtractor {
  def unapplySeq[T](s: Set[T]): Option[Seq[T]] = Some(s.toSeq)
}
Run Code Online (Sandbox Code Playgroud)

例如:

scala> Set(1, 2, 3) match {
     |   case SetExtractor(x, xs @ _*) => println(s"x: $x\nxs: $xs")
     | }
x: 1
xs: ArrayBuffer(2, 3)
Run Code Online (Sandbox Code Playgroud)

  • 尼斯.为了清楚凯文:因为在集合上没有定义的顺序,你应该*不要使用具有实际值的SetExtractor,例如`case SetExtractor(1,xs @ _*)=> ...`; 它恰好与`Set(1,2,3)`一起使用但通常不会起作用,例如使用`Set(1,2,3,4,5)`.Daniel提供了这种方法,允许解构绑定从Set中选择任意元素.还要注意,余数xs是一个ArrayBuffer,所以如果你想把它作为一个Set使用`xs.toSet`. (4认同)

pag*_*_5b 7

Set不是case class,也没有unapply方法.

这两件事暗示你不能直接在a上进行模式匹配Set.
(更新:除非你定义自己提取Set,如丹尼尔正确地显示在他的回答)

你应该找到一个替代方案,我建议使用折叠功能

def union(s: Set[Int], t: Set[Int]): Set[Int] = 
    (s foldLeft t) {case (t: Set[Int], x: Int) => t + x}
Run Code Online (Sandbox Code Playgroud)

或者,避免使用大多数显式类型注释

def union(s: Set[Int], t: Set[Int]): Set[Int] =
  (s foldLeft t)( (union, element) => union + element )
Run Code Online (Sandbox Code Playgroud)

甚至更短

def union(s: Set[Int], t: Set[Int]): Set[Int] =
  (s foldLeft t)(_ + _)
Run Code Online (Sandbox Code Playgroud)

这将累积sover 的元素,t逐个添加它们


折页

以下是折叠操作的文档,如果需要参考:

foldLeft[B](z: B)(op: (B, A) ? B): B
Run Code Online (Sandbox Code Playgroud)

将二元运算符应用于起始值以及此集合的所有元素,从左到右.

注意:除非订购了基础集合类型,否则可能会为不同的运行返回不同的结果.或者运算符是关联的和可交换的.

B the result type of the binary operator.
z the start value.
op the binary operator.
returns the result of inserting op between consecutive elements of this set, going left to right with the start value z on the left:

op(...op(z, x_1), x_2, ..., x_n)
where x1, ..., xn are the elements of this set.
Run Code Online (Sandbox Code Playgroud)


Dan*_*yel 6

首先,您isEmpty将捕获每个,Set因为它是此上下文中的变量。在 Scala 中,常量以大写字母开头,并且仅当此条件成立时才将其视为常量。所以小写字母会将任何分配给SetisEmpty您在寻找吗EmptySet?)

这里可以看出,模式匹配对于 s 来说似乎并不是很可取Set。您可能应该显式地将 转换Set为 aListSeq( toList/ toSeq)

object Foo {
    def union(s: Set[Int], t: Set[Int]): Set[Int] = t.toList match {
        case Nil => s
        case (x::xs)  => union(s + x, xs.toSet)
        case _       => throw new Error("bad input")
    }
}
Run Code Online (Sandbox Code Playgroud)