使用集合进行 Scala 模式匹配

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15163904/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:01:22  来源:igfitidea点击:

Scala Pattern Matching with Sets

scalapattern-matching

提问by Kevin Meredith

The following doesn't work.

以下不起作用。

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

error: not found: type xs

错误:未找到:输入 xs

How can I pattern match over a set?

如何在集合上进行模式匹配?

回答by Daniel C. Sobral

Well, x:xsmeans xof type xs, so it wouldn't work. But, alas, you can't pattern match sets, because sets do not have a defined order. Or, more pragmatically, because there's no extractor on Set.

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

You can always define your own, though:

不过,您始终可以定义自己的:

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

For example:

例如:

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

回答by pagoda_5b

Setis not a case classand doesn't have a unapplymethod.

Set不是一个case class并且没有一个unapply方法。

These two things imply that you cannot pattern match directly on a Set.
(update: unless you define your own extractorfor Set, as Daniel correctly shows in his answer)

这两件事意味着您不能直接在Set.
更新:除非你定义自己的提取Set他的回答,丹尼尔显示正确)

You should find an alternative, I'd suggest using a fold function

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

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

or, avoiding most explicit type annotation

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

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

or even shorter

甚至更短

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

This will accumulate the elements of sover t, adding them one by one

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



folding

折叠式的

Here are the docsfor the fold operation, if needed for reference:

如果需要参考,这里是折叠操作的文档

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

Applies a binary operator to a start value and all elements of this set, going left to right.

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

Note: might return different results for different runs, unless the underlying collection type is ordered. or the operator is associative and commutative.

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

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.

回答by Danyel

First of all, your isEmptywill catch every Setsince it's a variable in this context. Constants start with an upper case letter in Scala and are treated only as constants if this condition holds. So lowercase will assign any Setto isEmpty(were you looking for EmptySet?)

首先,您isEmpty将捕获每一个,Set因为它在此上下文中是一个变量。常量在 Scala 中以大写字母开头,如果此条件成立,则仅将其视为常量。所以小写将分配任何SetisEmpty(你在找EmptySet吗?)

As seen here, it seems that pattern matching isn't very preferable for Sets. You should probably explicitly convert the Setto a Listor Seq(toList/ toSeq)

这里所见,似乎模式匹配对于Sets并不是很可取。您可能应该明确地将 the 转换Set为 a Listor Seq( 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")
    }
}

回答by Peter Schmitz

This is what I can come up with:

这是我能想出的:

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

回答by Dalius ?idlauskas

    t match {
      case s if s.nonEmpty => // non-empty 
      case _ => // empty
    }