Scala Pattern Matching

The following does not 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

How can I match a pattern by set?

+13
scala pattern-matching
source share
5 answers

Well, x:xs means x type xs , so it won't work. But, alas, you cannot create set mappings because sets do not have a specific order. Or more pragmatic, because there is no extractor on Set .

You can always define your own:

 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) 
+18
source share

Set not a case class and does not have an unapply method.

These two things mean that you cannot directly match patterns in Set .
( update : if you don't define your own extractor for Set , as Daniel correctly shows in his answer)

You should find an alternative, I would suggest using the bend function

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

or avoiding the most explicit type annotations

 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 accumulates s elements by t , adding them one by one


folding

Here are the documents for the folding operation, if necessary for reference:

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

Applies the binary operator to the initial value and all elements of this set from left to right.

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

 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. 
+7
source share

First of all, your isEmpty will catch every Set , since it is a variable in this context. Constants begin with an uppercase letter in Scala and are considered only as constants if this condition is met. Thus, lowercase letters will assign any Set to isEmpty (did you EmptySet ?)

As you can see here , it seems that pattern matching is not very preferable for Set s. You should probably explicitly convert Set to List or 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") } } 
+4
source share

Here 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") } 
+1
source share
  t match { case s if s.nonEmpty => // non-empty case _ => // empty } 
0
source share

All Articles