Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala pattern matching: How to match on an element inside a list?

Is it possible to rewrite the following code using Scala pattern matching?

val ls: List[String] = ??? // some list of strings

val res = if (ls.contains("foo")) FOO
     else if (ls.contains("bar")) BAR
     else SOMETHING_ELSE
like image 207
Alex Vayda Avatar asked Feb 01 '13 09:02

Alex Vayda


People also ask

How pattern matching works in a function's parameter list?

Pattern matching tests whether a given value (or sequence of values) has the shape defined by a pattern, and, if it does, binds the variables in the pattern to the corresponding components of the value (or sequence of values). The same variable name may not be bound more than once in a pattern.

Does Scala have pattern matching?

Pattern matching is the second most widely used feature of Scala, after function values and closures. Scala provides great support for pattern matching, in processing the messages. A pattern match includes a sequence of alternatives, each starting with the keyword case.

How does Scala pattern matching work?

Pattern matching is a mechanism for checking a value against a pattern. A successful match can also deconstruct a value into its constituent parts. It is a more powerful version of the switch statement in Java and it can likewise be used in place of a series of if/else statements.

What is case _ in Scala?

case _ => does not check for the type, so it would match anything (similar to default in Java). case _ : ByteType matches only an instance of ByteType . It is the same like case x : ByteType , just without binding the casted matched object to a name x .


2 Answers

You can add if conditions to matches like this:

ls match {
  case x if x.contains("foo") => // FOO
  case x if x.contains("bar") => // BAR
  case _ => // ELSE
}

However, it is not the nicest way, as each if check needs to traverse the list, so this doesn't scale well. There are various different ways to deal with this problem, but we would need to know more about your intensions, as normally the runtime semantics would differ from your code (for example, you could recursively traverse the list looking for either "foo" or "bar", but that would assume you only have either one in the list).

like image 199
Frank Avatar answered Nov 07 '22 04:11

Frank


You could implement this using a function like

def onContains[T](xs: Seq[String], actionMappings: (String, T)*): Option[T] = {
  actionMappings collectFirst {
    case (str, v) if xs contains str => v
  }
}

And use it like this:

val x = onContains(items,
  "foo" -> FOO,
  "bar" -> BAR
)
like image 24
Marius Danila Avatar answered Nov 07 '22 04:11

Marius Danila