can I combine multiple string matching cases in scala? - scala

Can I combine the following two cases into one case clause since they both do the same thing?
e match {
case "hello" => e + "world"
case "hi" => e + "world
}
Also, what about if I want to match using startsWith e.g.,
e match { case e.startsWith("he") | e.startsWith("hi") => ... }

Yes you can simply use or (|) to match one of the pattern,
scala> "hi" match { case "hello" | "hi" => println("fantastic") case _ => println("very very bad")}
fantastic
scala> "hello" match { case "hello" | "hi" => println("fantastic") case _ => println("very very bad")}
fantastic
scala> "something else" match { case "hello" | "hi" => println("fantastic") case _ => println("very very bad")}
very very bad
You can also use regex to pattern match, especially useful when there are many criterias to match,
scala> val startsWithHiOrHello = """hello.*|hi.*""".r
startsWithHiOrHello: scala.util.matching.Regex = hello.*|hi.*
scala> "hi there" match { case startsWithHiOrHello() => println("fantastic") case _ => println("very very bad")}
fantastic
scala> "hello there" match { case startsWithHiOrHello() => println("fantastic") case _ => println("very very bad")}
fantastic
scala> "non of hi or hello there" match { case startsWithHiOrHello() => println("fantastic") case _ => println("very very bad")}
very very bad
Refer to Scala multiple type pattern matching and Scala match case on regex directly

Related

In Scala how to access match case value in each case block

I want to access to the case value in the case block
val a = "hello"
a match {
case "hello" | "Hi" =>
println("hello") // how can I access the right case value? Hello or Hi?
case _ =>
print("NA")
}
You can reference the matched value like so:
a match {
case str # ("hello" | "Hi") => println(str)
case _ => print("NA")
}
Another way could be -
a match {
case str if str == "hello" | str == "Hi" => println(str)
case _ => println("NA")
}

Best functional way of handling conditional flows

I have an Option of String which may be empty too. I have written following code to handle different branches of flow:
input match {
case Some(val) => {
val match {
case "sayHi" => "Hi"
case "sayHello" => "Hello"
case _ => extractFromAnotherInput
}
}
None => extractFromAnotherInput
}
private def extractFromAnotherInput = {
anotherInput match {
case a => ....
case b => ....
}
}
Is this a good way of handling code branches in a functional language or it can be done in a better way?
You don't have to nest the matches:
input match {
case Some("sayHi") => "Hi"
case Some("sayHello") => "Hello"
case _ => extractFromAnotherInput
}
You can also combine this input with "another", and "strip" he option before doing the match:
input.getOrElse(anotherInput) match {
case "sayHi" => "Hi"
case "sayHello" => "Hello"
case a => ...
case b => ...
}
I would go with Dima's solution. Or if you want to use some method on Option:
input.collect{
case "sayHi" => "Hi"
case "sayHello" => "Hello"
}
.getOrElse(extractAnotherInput)
Just because, I would like to propose an alternative to Levi's answer; just to remark this is more of a matter of opinion.
input.filter(_.nonEmpty).fold(ifEmpty = extractAnotherInput) {
case "sayHi" => "Hi"
case "sayHello" => "Hello"
}
This is a matter of style: I personally dislike pattern-matching on Option, but that's idiosyncratic (I also may be the only Scala programmer who generally dislikes the for notation, but that's neither here nor there).
I'd express that as
input.flatMap { v =>
v match {
case "sayHi" => Some("Hi")
case "sayHello" => Some("Hello")
case _ => None
}
}.getOrElse(extractAnotherInput)
If overfitting to this example (exploiting the fact that I can uniformly transform sayHi and sayHello)
input.filter(v => v == "sayHi" || v == "sayHello")
.map(_.drop(3))
.getOrElse(extractAnotherInput)

in scala why does for yield return option instead of string

I'm new to scala I'm trying to understand for/yield and don't understand why the following code returns an option not a String
val opString: Option[String] = Option("test")
val optionStr : Option[String] = for {
op <- opString
} yield {
opString match {
case Some(s) => s
case _ => "error"
}
}
A for-expression is syntactic sugar for a series of map, flatMap and withFilter calls. Your specific for-expression is translated to something like this:
opString.map(op => opString match {
case Some(s) => s
case _ => "error"
})
As you can see, your expression will just map over opString and not unwrap it in any way.
Desugared expression for your for ... yield expression is:
val optionStr = opString.map {
op =>
opString match {
case Some(s) => s
case _ => "error"
}
}
The type of opString match {...} is String, so the result type of applying map (String => String) to Option[String] is Option[String]
What you're looking for is getOrElse:
opString.getOrElse("error")
This is equivalent to:
opString match {
case Some(s) => s
case _ => "error"
}

Pattern matching a BitSet in Scala

Is there an easy/best way to get a BitSet I can pattern match like a list?
val btst = BitSet(1,2,3,4)
btst match {
...
case head :: tail => tail
}
By definition a set is an unordered collection, and pattern matching over such one is error-prone. Convert it to list if you want to... Also, you should not rely on head and tail to always return the same thing.
A BitSet is ordered, but extractorless.
Edit: but not humorless.
object |<| {
def unapply(s: BitSet): Option[(Int, BitSet)] =
if (s.isEmpty) None
else Some((s.head, s.tail))
}
def flags(b: BitSet) = b match {
case f"5 || 10" => println("Five and dime") // alas, never a literal
case 5 |<| any => println(s"Low bit is 5iver, rest are $any")
case i |<| any => println(s"Low bit is $i, rest are $any")
case _ => println("None")
}
def dump(b: BitSet) = println(b.toBitMask.mkString(","))
val s = BitSet(5, 7, 11, 17, 19, 65)
dump(s)
// ordinary laborious tests
s match {
case x if x == BitSet(5) => println("Five")
case x if x == BitSet(5,7,11,17,19,65) => println("All")
case x if x(5) => println("Five or more")
case _ => println("None")
}
// manually matching on the mask is laborious
// and depends on the bit length
s.toBitMask match {
case Array(2L) => println("One")
case Array(657568L) => println("First word's worth")
case Array(657568L, _) => println("All")
case _ => println("None")
}
// or truncate for special case
s.toBitMask(0) match {
case 2L => println("One")
case 657568L => println("First word's worth")
case _ => println("None")
}

Scala: Pattern matching when one of two items meets some condition

I'm often writing code that compares two objects and produces a value based on whether they are the same, or different, based on how they are different.
So I might write:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) => "b"
case (None, Some(value)) => "b"
case _ = > "c"
}
Those 2nd and 3rd cases are the same really, so I tried writing:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) || (None, Some(value)) => "b"
case _ = > "c"
}
But no luck.
I encounter this problem in a few places, and this is just a specific example, the more general pattern is I have two things, and I want to know if one and only one of them meet some predicate, so I'd like to write something like this:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case OneAndOnlyOne(value, v: Option[Foo] => v.isDefined ) => "b"
case _ = > "c"
}
So the idea here is that OneAndOnlyOne can be configured with a predicated (isDefined in this case) and you can use it in multiple places.
The above doesn't work at all, since its backwards, the predicate needs to be passed into the extractor not returned.
How about something like this?
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case new OneAndOnlyOne(v: Option[Foo] => v.isDefined )(value) => "b"
case _ = > "c"
}
with:
class OneAndOnlyOne[T](predicate: T => Boolean) {
def unapply( pair: Pair[T,T] ): Option[T] = {
val (item1,item2) = pair
val v1 = predicate(item1)
val v2 = predicate(item2)
if ( v1 != v2 )
Some( if ( v1 ) item1 else item2 )
else
None
}
}
But, this doesn't compile.
Can anyone see a way to make this solution work? Or propose another solution? I'm probably making this more complicated than it is :)
I think you're asking two slightly different questions.
One question is how to use "or" in switch statements. || doesn't work; | does. And you can't use variables in that case (because in general they might match different types, which renders the type confusing). So:
def matcher[T](a: (T,T)) = {
a match {
case (Some(x),Some(y)) => "both"
case (Some(_),None) | (None,Some(_)) => "either"
case _ => "none"
}
}
Another question is how to avoid having to do this over and over, especially if you want to be able to get at the value in the tuple. I've implemented a version here for Option, but you could use an unwrapped tuple and a boolean.
One trick to achieve this is that to prewrap the values before you start matching on it, and then use your own matching constructs that do what you want. For instance,
class DiOption[+T] {
def trinary = this
}
case class Both[T](first: T, second:T) extends DiOption[T] { }
case class OneOf[T](it: T) extends DiOption[T] { }
case class Neither() extends DiOption[Nothing] { }
implicit def sometuple2dioption[T](t2: (Option[T],Option[T])): DiOption[T] = {
t2 match {
case (Some(x),Some(y)) => Both(x,y)
case (Some(x),None) => OneOf(x)
case (None,Some(y)) => OneOf(y)
case _ => Neither()
}
}
// Example usage
val a = (Some("This"),None)
a trinary match {
case Both(s,t) => "Both"
case OneOf(s) => "Just one"
case _ => "Nothing"
}
If you have to support arbitrary predicates you can derive from this (which is based on Daniel's idea):
List(v1, v2) filter (_ %2 == 0) match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
the definition of the function:
def filteredMatch[T,R](values : T*)(f : T => Boolean)(p: PartialFunction[List[T], R]) : R =
p(List((values filter f) :_* ))
Now you can use it like this:
filteredMatch(v1,v2)(_ %2 == 0){
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
I'm not so sure if it's a good idea (i.e. readable). But a neat exercise nonetheless.
It would be nice if you could match on tuples: case (value1, value2) => ... instead of lists.
How about this:
Welcome to Scala version 2.8.0.r20327-b20091230020149 (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def m(v1: Any,v2: Any) = (v1,v2) match {
| case (Some(x),Some(y)) => "a"
| case (Some(_),None) | (None,Some(_)) => "b"
| case _ => "c"
| }
m: (v1: Any,v2: Any)java.lang.String
scala> m(Some(1),Some(2))
res0: java.lang.String = a
scala> m(Some(1),None)
res1: java.lang.String = b
scala> m(None,None)
res2: java.lang.String = c
scala>
You should be able to do it if you define it as a val first:
val MyValThatIsCapitalized = new OneAndOnlyOne(v: Option[Foo] => v.isDefined )
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case MyValThatIsCapitalized(value) => "b"
case _ = > "c"
}
As implied by the name, the name of the val containing the extractor object must be capitalized.
On Scala 2.8:
val result = List(v1,v2).flatten match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ = > "c"
}
On Scala 2.7, however, you need a type hint to make it work. So, assuming value is Int, for instance, then:
val result = (List(v1,v2).flatten : List[Int]) match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ = > "c"
}
The funny thing about it is that I misread "first" as "list" on Mitch Blevins answer, and that gave me this idea. :-)
Since you already matched against (Some(x), Some(y)), you may match against (None, None) explicitly, and the remaining cases are (Some(x), None) and (None, Some(y)):
def decide [T](v1: Option[T], v2:Option[T]) = (v1, v2) match {
case (Some (x), Some (y)) => "a"
case (None, None) => "c"
case _ => "b"
}
val ni : Option [Int] = None
decide (ni, ni) // c
decide (Some (4), Some(3)) // a
decide (ni, Some (3)) // b
decide (Some (4), ni) // b