Scala pattern matching: How to match on an element inside a list?
Solution 1
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
)
Solution 2
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).
Solution 3
As Frank's answer says, it is possible, but expensive if you would do it the dirty way.
It depends on what you want to do. Do you want to return the index of that "foo" or "bar" (for example)? Then you would do something like this:
def indexOf[T]: (List[T], T) => Int = (ls, x) => ls match {
case Nil => -1
case e::es if( e.equals(x) ) => 0
case e::es => val i = indexOf( es, x ); if( i < 0 ) i else i + 1
}
This code is not tested, but you get the idea.
Alex Vayda
Enthusiastic full-stack software engineer and active open-source contributor. Scala, Java, TypeScript, JavaScript Spring, Hibernate Angular Apache Spark MongoDb, ArangoDb Oracle, PostgreSQL ElasticSearch, Solr
Updated on July 09, 2022Comments
-
Alex Vayda almost 2 years
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
-
Alex Vayda over 11 yearsI thought did it that way but 'case' looks redundant as I have those 'if's anyway. I would want to write something like { case _ :: "foo" :: _ => ??? }
-
Alex Vayda over 11 yearsYes my cases should return a value (see my comment to the question). I like your approach, although it is much less concise than simple if-else construction. But I would need to have my constants (foo, bar, baz etc) to be listed twice in a code. I have a couple of dozens of them so I would avoid this.
-
Kevin Meredith almost 11 yearsthanks for answer. What does the * mean in
actionMappings: (String, T)*
? -
Marius Danila almost 11 yearsIt allows to define a method to have a variable number of arguments which can be accessed as a
Seq
collection. tutorialspoint.com/scala/functions_variable_arguments.htm