18

以下不起作用。

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")
    }
}

错误:未找到:输入 xs

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

4

5 回答 5

21

好吧,type 的x:xs手段,所以它不起作用。但是,唉,你不能对集合进行模式匹配,因为集合没有定义的顺序。或者,更务实的是,因为.xxsSet

但是,您始终可以定义自己的:

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

例如:

scala> Set(1, 2, 3) match {
     |   case SetExtractor(x, xs @ _*) => println(s"x: $x\nxs: $xs")
     | }
x: 1
xs: ArrayBuffer(2, 3)
于 2013-03-01T21:44:24.343 回答
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}

或者,避免最显式的类型注释

def union(s: Set[Int], t: Set[Int]): Set[Int] =
  (s foldLeft t)( (union, element) => union + element )

甚至更短

def union(s: Set[Int], t: Set[Int]): Set[Int] =
  (s foldLeft t)(_ + _)

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


折叠式的

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

foldLeft[B](z: B)(op: (B, A) ⇒ B): B

将二元运算符应用于起始值和该集合的所有元素,从左到右。

注意:可能会针对不同的运行返回不同的结果,除非对基础集合类型进行了排序。或运算符是关联和可交换的。

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.
于 2013-03-01T18:02:16.420 回答
6

首先,你isEmpty会抓住每一个Set,因为它在这种情况下是一个变量。常量在 Scala 中以大写字母开头,并且仅在此条件成立时才被视为常量。所以小写将分配任何SetisEmpty(你在找EmptySet吗?)

如此处所见,似乎模式匹配对于Sets 不是很可取。您可能应该将 显式转换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")
    }
}
于 2013-03-01T17:59:45.083 回答
2

这是我能想到的:

object Contains {
  class Unapplier[T](val t: T) {
    def unapply(s: Set[T]): Option[Boolean] = Some(s contains t)
  }
  def apply[T](t: T) = new Unapplier(t)
}

object SET {
  class Unapplier[T](val set: Set[T]) {
    def unapply(s: Set[T]): Option[Unit] = if (set == s) Some(Unit) else None
  }
  def apply[T](ts: T*) = new Unapplier(ts.toSet)
}

val Contains2 = Contains(2)
val SET123 = SET(1, 2, 3)

Set(1, 2, 3) match {
  case SET123()         => println("123")
  case Contains2(true)  => println("jippy")
  case Contains2(false) => println("ohh noo")
}
于 2013-10-02T20:28:57.940 回答
1
    t match {
      case s if s.nonEmpty => // non-empty 
      case _ => // empty
    }
于 2019-04-29T10:12:17.970 回答