【问题标题】:Is it possible to pattern match on Iterable是否可以在 Iterable 上进行模式匹配
【发布时间】:2018-10-11 13:36:51
【问题描述】:

它有一种优雅的方式来对 scala Iterable[A] 集合进行模式匹配,检查它是否为空,是否仅包含一个元素(并获取它),是否包含恰好 N 个元素(并获取它们),如果它包含至少一个或多个元素(并获取它或它们),等等。

使用List 这很简单,但我无法让Iterable 工作。

【问题讨论】:

  • 看起来你总是使用整个Iterable。如果one element => get it,如果iterable.size >=1 get it,如果n elements => get it,这意味着这些条件将始终为真。您唯一错过的是 0 elem。
  • 它们只是可能匹配的示例

标签: scala pattern-matching


【解决方案1】:

你想通过以下方式进行模式匹配吗?

val it: Iterable[Int] = ...
it match {
  case Iterable(1, a, b) => ...
  case Iterable(a, b) => ...
  case Iterable() =>
}

如果是,实际上你不能这样做,因为 Iterable 的伴生对象没有unapplySeq 方法。因此,最简单的方法是将Iterable 显式转换为Seq

val it: Iterable[Int] = ...
it.toSeq match {
  case Seq(1, a, b) => ...
  case Seq(a, b) => ...
  case Seq() =>
}

或者,如果您不想每次都手动将Iterable 转换为Seq,您可以使用以下代码:

object iterable {
  def unapplySeq[A](it: Iterable[A]): Option[Seq[A]] = Some(it.toSeq)
}
val it: Iterable[Int] = ...
it match {
  case iterable(1, a, b) => ...
  case iterable(a, b) => ...
  case iterable() =>
}

但请注意,底层集合可能不是Seq。这种方法可能会导致将整个Iterable 复制到一个新集合中。

编辑:

Iterable 可能是无限的。在这种情况下,.toSeq 可能会使您的程序崩溃。 所以最安全的方法是在模式匹配之前调用.take(n)

【讨论】:

  • 非常好的提示,谢谢。请注意 toSeq 不会因无限的 Iterable 集合而终止。我们可以先调用 take(n) 然后调用 toSeq 或直接调用 toList 并使用列表模式匹配。我想直接在 Iterable 上做而不转换它,但这似乎是不可能的。无论如何,请修改您的答案,我们会以我们找到的最安全和最好的方式记录下来。
【解决方案2】:

这个怎么样:

   object Example extends App {

     val myIterable: Iterable[Int] = List(1,2).toIterable

     myIterable match {
        case Nil =>
            println(s" list is empty")
        case a::Nil =>
            println(s" list contains 1 elements $a")
        case a::b::Nil =>
            println(s" list contains 2 elements $a and $b")
    }
  }

【讨论】:

  • 这仅是因为在您的示例中原始对象是一个列表。我觉得一般情况下是行不通的,请尝试用数组快速检查一下。
猜你喜欢
  • 2016-11-12
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 1970-01-01
  • 2017-03-25
  • 1970-01-01
  • 2016-03-24
相关资源
最近更新 更多