Scala: build Map with pattern matching - scala

I am trying to build a Map[String, Any] like this:
Map(
somevalues match {
Some(v) => ("myvalues -> v)
None => ???
},
othervalues match {
Some(v) => ("othervalues -> v)
None => ???
},
...etc
)
which value should I use for the none case as I don't want to insert anything in the map in that case?

Consider
List(
someValues match {
case Some(v) => Some("myValues" -> v)
case None => None
},
otherValues match {
case Some(v) => Some("otherValues" -> v)
case None => None
},
...
).flatten.toMap
or shortened:
List(
someValues.map("myValues" -> _),
otherValues.map("otherValues" -> _),
...
).flatten.toMap

Related

Returning List[Double], Map[String, Double] from a list of Doubles

I'm trying to return a tuple of a list and map. I've already gotten the list to compile correctly however I'm not sure how to use a map and list to get a map of the keys and values that match what's in my list. Here is what I have so far:
I've been able to achieve returning a list. However I need to return (List[Double], Map[String, Double])
def emulateSingleInstruction(stack: List[Double],
env: Map[String, Double],
ins: StackMachineInstruction): (List[Double], Map[String, Double]) = {
ins match{
case AddI => stack match{
case i1 :: i2 :: tail => (i1 + i2 :: tail, env)
case _ => throw new IllegalArgumentException()
}
//USE V1 and V2
case SubI => stack match{
case i1 :: i2 :: tail => (i1 - i2 :: tail, env)
case _ => throw new IllegalArgumentException()
}
case MultI => stack match{
case i1 :: i2 :: tail => (i1 * i2 :: tail, env)
case _ => throw new IllegalArgumentException()
}
//USE V1 and V2
case DivI => stack match{
case i1 :: i2 :: tail => (i1 / i2 :: tail, env)
case _ => throw new IllegalArgumentException()
}
case ExpI => stack match{
case Nil => throw new IllegalArgumentException()
case head :: tail => {
(scala.math.exp(head) :: tail,env)
}
}
case LogI => stack match{
case Nil => throw new IllegalArgumentException()
case head :: tail => {
if (head > 0){(scala.math.log(head) :: tail,env)}
else{ throw new IllegalArgumentException()}
}
}
case SinI => stack match{
case Nil => throw new IllegalArgumentException()
case head :: tail => {
(scala.math.sin(head) :: tail,env)
}
}
case CosI => stack match{
case Nil => throw new IllegalArgumentException()
case head :: tail => {
(scala.math.cos(head) :: tail,env)
}
}
case PushI(f) => (f :: stack,env)
case PopI => stack match{
case Nil => throw new IllegalArgumentException()
case i1 :: tail => {
(tail,env)
}
}
}
}
Since your example operation seems not to modify the environment but only the stack, I understand you are simply asking how to combine the new stack and the environment in the return value.
def emulateSingleInstruction(stack: List[Double],
env: Map[String, Double],
ins: StackMachineInstruction): (List[Double], Map[String, Double]) = {
val newStack = ins match {
case AddI => // your code. Looks good...
}
val newEnv = // expression that evaluates to the updated environment
(newStack, newEnv)
}

Scala pattern matching for tuple with options still needs unwrapping for the some case

f(Int) is an function that returns an Option[Int].
def findIntPair(x: Int, y: Int): (Int, Int) = {
(f(x), f(y)) match {
case (None, None) || (None, _) || (_, None) => fail("Unable to find the pair" )
case (a, b) => (a.get, b.get) // why I still need to unwrap by get
}
}
Why does the last case(a, b) not unwrap them into Int but still keep them as Option[Int]?
FYI: I'm using intelliJ IDEA.
You need to pattern match with Some:
def findIntPair(x: Int, y: Int): (Int, Int) = {
(f(x), f(y)) match {
case (None, None) || (None, _) || (_, None) => fail("Unable to find the pair" )
case (Some(a), Some(b)) => (a, b)
}
}
A bit cleaner using a catch-all case _:
def findIntPair(x: Int, y: Int): (Int, Int) = {
(f(x), f(y)) match {
case (Some(a), Some(b)) => (a, b)
case _ => fail("Unable to find the pair" )
}
}
I think the right solution is that you do that by this way:
(f(x), f(y)) match {
case (None, None) | (None, _) | (_, None) => fail("Unable to find the pair" )
case (Some(a), Some(b)) => (a, b)
}
}
Thats because:
def findIntPair(x: Int, y: Int): (Int, Int) = {
(f(x), f(y)) match {
case (None, None) || (None, _) || (_, None) => fail("Unable to find the pair" )
case (a, b) => (a.get, b.get) //here f(x) = a and f(y) = b
}
}
You want something like this:
def findIntPair(x: Int, y: Int): (Int, Int) = {
(f(x), f(y)) match {
case (None, None) || (None, _) || (_, None) => fail("Unable to find the pair" )
case (Some(a), Some(b)) => (a, b)
}
}
But thats not the best way to do that i think this is better:
def findIntPair(x: Int, y: Int): (Int, Int) = {
if(f(x).isDefined && f(y).isDefined) (f(x).get,f(y).get)
else fail("Unable to find the pair" )
}
Here is an alternative way of expressing this logic:
def findIntPair(x: Int, y: Int): Option[(Int, Int)] =
for {
a <- f(x)
b <- f(y)
} yield (a,b)
This has the advantage that it will not compute f(y) if f(x) returns None. This version returns an Option so that the error can be processed later, but you can process it inside the function like this:
def findIntPair(x: Int, y: Int): (Int, Int) =
(
for {
a <- f(x)
b <- f(y)
} yield (a, b)
).getOrElse(fail("Unable to find the pair"))
Note that this assumes that fail returns (Int, Int), which is what would be necessary for the code in the question to work.

Composing PartialFunctions with orElse when there is a wildcard case

Is it possible to orElse compose two PartialFunctions when the first function has case _ => wildcard pattern that matches anything thus in effect being a total function.
For example, given
val pf1: PartialFunction[Int, String] = {
case 1 => "foo"
case 2 => "bar"
case _ => "wildcard"
}
val pf2: PartialFunction[Int, String] = {
case 3 => "baz"
case _ => "wildcard"
}
then, out-of-the-box
(pf1 orElse pf2)(3)
outputs wildcard. However, assuming we cannot modify pf1, can we compose with pf2 using some compfn such that we get in effect
{
case 1 => "foo"
case 2 => "bar"
case 3 => "baz"
case _ => "wildcard"
}
where (pf1 compfn pf2)(3) would output baz?
You can turn pf1 into a true partial function by doing a second match to convert the "wildcard" result to a failed match.
val pf3: PartialFunction[Int, String] = (i: Int) => pf1(i) match {
case s if s != "wildcard" => s
}
And then
(pf3 orElse pf2)(3)
If you want the precise syntax you showed then you need to use an implicit class:
implicit class addCompfn(f1: PartialFunction[Int, String]) {
def compfn(f2: PartialFunction[Int, String]) = (i: Int) => f1(i) match {
case s if s != "wildcard" => s
case s => f2(i)
}
}
And then
(pf1 compfn pf2)(3)
Why not opting for something like this:
val pf1: PartialFunction[Int, String] = {
case 1 => "foo"
case 2 => "bar"
}
val pf2: PartialFunction[Int, String] = {
case 3 => "baz"
}
def composeOrElseWildcard(input: Int) = (pf1 orElse pf2).applyOrElse(input,(_: Int) => "wildcard")
Otherwise, to me, there are no solution to get rid of wildcard pattern effect in pf1.
( composeOrElseWildcard(3) gives "baz" and composeOrElseWildcard(4) gives "wildcard" )

Return a different type according to an input parameter

Let's see an example (it's a naive example but sufficient to illustrate the problem).
def produce(l: List[Int]) : Any =
l match {
case List(x) => x
case List(x, y) => (x, y)
}
val client1 : Int = produce(List(1)).asInstanceOf[Int]
Drawback : client need to cast !
def produce2[A](l: List[Int])(f: List[Int] => A) = {
f(l)
}
val toOne = (l: List[Int]) => l.head
val toTwo = (l: List[Int]) => (l.head, l.tail.head)
val client2 : Int = produce2(List(1))(toOne)
Drawback : type safety, i.e. we can call toTwo with a singleton List.
Is there a better solution ?
If you only have two possible return values you could use Either:
def produce(l : List[Any]) : Either[Any, (Any, Any)] = l match {
case List(x) => Left(x)
case List(x, y) => Right((x, y))
}
If you don't want to create an Either, you could pass a function to transform each case:
def produce[A](l : List[Int])(sf: Int => A)(pf: (Int, Int) => A): A = l match {
case List(x) => sf(x)
case List(x, y) => pf(x, y)
}
Will this work?
def produce(l: List[Int]) = {
l match {
case List(x) => (x, None)
case List(x,y) => (x,y)
case Nil => (None, None)
}
}
or even better, to avoid match errors on lists longer than 2 elements:
def produce(l: List[Int]) =
l match {
case x :: Nil => (x, None)
case x :: xs => (x,xs.head)
case Nil => (None, None)
}

Generic unapply method for different types of List

Is there a way to generalize this code with generics?
object ListInt {
def unapply(o: Any): Option[List[Int]] = o match {
case lst: List[_] if(lst.forall(_.isInstanceOf[Int])) =>
Some(lst.asInstanceOf[List[Int]])
case _ => None
}
}
object ListDouble {
def unapply(o: Any): Option[List[Double]] = o match {
case lst: List[_] if(lst.forall(_.isInstanceOf[Double])) =>
Some(lst.asInstanceOf[List[Double]])
case _ => None
}
}
object ListString {
def unapply(o: Any): Option[List[String]] = o match {
case lst: List[_] if(lst.forall(_.isInstanceOf[String])) =>
Some(lst.asInstanceOf[List[String]])
case _ => None
}
}
val o: Any = List("a", "b", "c")
o match {
case ListInt(lst) => println(lst.sum)
case ListDouble(lst) => println(lst.product)
case ListString(lst) => println(lst.mkString("(", ", ", ")"))
case _ => println("no match")
}
abstract class ListExtractor[A](implicit ct: reflect.ClassTag[A]) {
def unapply(o: Any): Option[List[A]] = o match {
case lst: List[_] if (lst.forall(ct.unapply(_).isDefined)) =>
Some(lst.asInstanceOf[List[A]])
case _ => None
}
}
object ListInt extends ListExtractor[Int ]
object ListString extends ListExtractor[String]
val o: Any = List("a", "b", "c")
o match {
case ListInt (lst) => println(lst.sum)
case ListString(lst) => println(lst.mkString("(", ", ", ")"))
case _ => println("no match")
}
It seems TypeTag is the way to go:
import scala.reflect.runtime.universe._
def foo[A: TypeTag](lst: A) = typeOf[A] match {
case t if t =:= typeOf[List[Int]] => lst.asInstanceOf[List[Int]].sum
case t if t =:= typeOf[List[Double]] => lst.asInstanceOf[List[Double]].product
case t if t =:= typeOf[List[String]] => lst.asInstanceOf[List[String]].mkString("(", ", ", ")")
}
println(foo(List("a", "b", "c")))
Check this excellent post for detailed explanation:
Scala: What is a TypeTag and how do I use it?