I know that in functional style all if-else
blocks replaced by pattern matching. But how I can handle Map
s with pattern matching in Scala? For example how I can rewrite this code in more functional style?
val myMap= getMap()
if(myMap.contains(x) && myMap.contains(y)) Some(myMap(x) + myMap(y))
else if(myMap.contains(x + y)){
val z = myMap(x + y)
if (z % 2 == 0) Some(z)
else None
}
else None
Using if-else
is totally acceptable for functional programming, because if-else
in Scala is merely an expression. The reasons to decide between if-else
and pattern-matching should be focused on improving readability, mainly.
Here's my try at rewriting your code. I'm actually not using pattern matching here, but a for
-comprehension to sum the values.
def sumOfValues = for{
mx <- myMap.get(x)
my <- myMap.get(y)
} yield mx + my
def valueOfSumIfEven = myMap.get(x+y).filter(_ % 2 == 0)
sumOfValues orElse valueOfSumIfEven
To answer your question directly - you can filter the cases with an additional if:
getMap match {
case myMap if (myMap.contains(x) && myMap.contains(y)) =>
Some(myMap(x) + myMap(y))
case myMap if (myMap.contains(x+y)) =>
myMap(x+y) match {
case z if (z % 2 == 0) => Some(z)
case _ => None
}
case _ => None
}
([edit: there actually is] Although there is are "else-if's" in Scala, ) this is actually a way of doing if-else-if-else (looking at the produced class-files this is what it actually does whereas if-else is equivalent to the ternary ?: in java, returning Unit implicitly when the final else is missing).
How about:
myMap.get(x)
.zip(myMap.get(y))
.headOption.map(x => x._1 + x._2)
.orElse(myMap.get(x + y)
.filter(__ % 2 == 0))
Well, you could write your test as follows:
myMap.get(x).flatMap(xVal => myMap.get(y).map(_ + xVal))
.orElse(myMap.get(x+y).filter(_ % 2 == 0))
But what you have already may just be clearer to anyone trying to understand the intent. Note that the first line (from flatMap to the end) can also be written as a for-comprehension, as shown in @ziggystar's answer).
Maybe the modulo test part could be rewritten as a match, if that feels cleaner:
if(myMap.contains(x) && myMap.contains(y))
Some(myMap(x) + myMap(y))
else myMap.get(x + y) match {
case Some(z) if (z % 2 == 0) => Some(z)
case _ => None
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With