Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern matching with more than one match

Consider the following Scala code.

val a = "both"

a match {
    case "both" | "foo" => println ("foo")   // case 1
    case "both" | "bar" => println ("bar")   // case 2
}

I would like match to work so that if a == "both", Scala will execute both cases. Is this possible or are there any alternatives to achieve what I want?

like image 523
Jus12 Avatar asked Sep 27 '11 07:09

Jus12


People also ask

What is multiple pattern matching?

The multi-pattern matching problem consists in finding all occurrences of the patterns from a finite set X in a given text T of. length n. We present a new and simple algorithm combining the ideas of the Aho–Corasick algorithm and the directed acyclic. word graphs.

What is pattern matching techniques?

In computer science, pattern matching is the act of checking a given sequence of tokens for the presence of the constituents of some pattern.

What is pattern matching give an example?

For example, x* matches any number of x characters, [0-9]* matches any number of digits, and . * matches any number of anything. A regular expression pattern match succeeds if the pattern matches anywhere in the value being tested.

What are the different operators for pattern matching?

Generally, the REGEXP_LIKE(column_name, 'regex') function is used for pattern matching in SQL. SQL also supports some operators that work similar to this function, these are: 'REGEXP' and 'RLIKE' operator.


2 Answers

Standard pattern-matching will always match on only exactly one case. You can get close to what you want by using the fact that patterns can be treated as partial functions (see the Language Specification, Section 8.5, Pattern Matching Anonymous Functions) and by defining your own matching operator, though:

class MatchAll[S](scrutinee : =>S) {
  def matchAll[R](patterns : PartialFunction[S,R]*) : Seq[R] = {
    val evald : S = scrutinee
    patterns.flatMap(_.lift(evald))
  }
}

implicit def anyToMatchAll[S](scrut : =>S) : MatchAll[S] = new MatchAll[S](scrut)

def testAll(x : Int) : Seq[String] = x matchAll (
  { case 2 => "two" },
  { case x if x % 2 == 0 => "even" },
  { case x if x % 2 == 1 => "neither" }
)

println(testAll(42).mkString(",")) // prints 'even'
println(testAll(2).mkString(","))  // prints 'two,even'
println(testAll(1).mkString(","))  // prints 'neither'

The syntax is slightly off the usual, but to me such a construction is still a witness to the power of Scala.

Your example is now written as:

// prints both 'foo' and 'bar'
"both" matchAll (
  { case "both" | "foo" => println("foo") },
  { case "both" | "bar" => println("bar") }
)

(Edit huynhjl pointed out that he gave a frighteningly similar answer to this question.)

like image 135
Philippe Avatar answered Oct 07 '22 22:10

Philippe


At risk of being Captain Obvious, in a case like this it would be simplest just to forget pattern matching and use if.

if (a == "both" || a == "foo") println("foo")
if (a == "both" || a == "bar") println("bar") 

If the repetition of a == worries you, you could instead write

if (Set("both", "foo")(a)) println("foo")
if (Set("both", "bar")(a)) println("bar")

using the fact that the apply method on Set does the same as contains, and is a bit shorter.

like image 20
Luigi Plinge Avatar answered Oct 07 '22 23:10

Luigi Plinge