Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to pattern match on Iterable

It there an elegant way to pattern match on a scala Iterable[A] collection, to check if it's empty, if it contains exactly one element (and get it), if it contains exactly N elements (and get them), if it contains at least one or more elements (and get it or them), and so on.

With List it's trivial, but I'm not able to have the equivalent for Iterable working.

like image 268
ragazzojp Avatar asked Mar 05 '23 06:03

ragazzojp


1 Answers

Do you want to do pattern matching in the following way?

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

If yes, actually you can't do it because Iterable's companion object doesn't have unapplySeq method. So the easiest way to do so is explicitly converting Iterable to Seq:

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

Or if you don't want to convert Iterable to Seq every time by hand, you can use something like this:

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() =>
}

But be aware that underlying collection may not be a Seq. This approach may lead to copying the whole Iterable into a new collection.

EDIT:

Iterable may be infinite. In this case .toSeq may crash your program. So the safest way will be calling .take(n) before pattern matching

like image 112
Vitalii Honta Avatar answered Mar 11 '23 04:03

Vitalii Honta