Let's suppose I have a class Toto with two optional fields :
case class Toto(a : Option[Int], b: Option[Int])
And a class Titi with one optional Toto :
case class Titi(c : Option[Toto])
We create an instance of a class Titi :
val test = Titi(Some(Toto(Some(1),Some(2))))
Now I want to access the second field of Toto in Titi variable by supposing that Titi or b can be equal to None but this statement is impossible :
test.c.getOrElse("Something").b.getOrElse(0)
How do I proceed to do so ?
You should use flatMap:
test.c.flatMap(_.b).getOrElse(0)
In a case in any place in the hierarchy there is None 0 will be returned.
If you have even a deeper object hierarchy with properties returning Option you can chain flatMap:
test.c
.flatMap(_.b)
.flatMap(_.d)
//...etc
Scala also has also the special syntax for unwrapping deeply nested monadic types, called for comprehension:
val result = for {
c <- test.c
a <- c.a
} yield a
result.getOrElse(0)
Under the hood, it is compiled to similar code as chained flatMap.
This basically works like this:
If c is None to gets directly to getOrElse and returns 0
If it's Some then it checks b, if it's None it goes to getOrElse if not then value wrapped in Some is returned.
In case you would want to return something different distinguishing which Option is None, then I would just use match:
test.c match {
case Some(c) => c.getOrElse(0)
// if you return String in one branch and integer in other then inferred type would be Any!
case None => "Something"
}
Your val test is wrong, it should be this
val test = Titi(Some(Toto(Some(1),Some(2))))
Other thing, in the getOrElse, you have to put a type that makes sense
test.c.getOrElse(Toto(None,None))
you can achieve it by pattern matching
val test: Titi = Titi(Some(Toto(Some(1), None)))
val res = test.c match {
case Some(Toto(_, Some(x))) => x
case _ => 0
}
result:
0
val x = test match {
case Titi(x) => {
x match {
case Some(x) => {
x.b match {
case Some(z) => z
case None => 1
}
}
case None => 1
}
}
case _ => 1
} //> x : Int = 2
u can use fold
test.c.fold(0)(_.b.fold(0)(i => i))
Related
I have a match statement like this:
val x = y match {
case array: Array[Float] => call z
case array: Array[Double] => call z
case array: Array[BigDecimal] => call z
case array: Array[_] => show error
}
How do I simplify this to use only two case statements, since first three case statements do same thing, instead of four.
Type erasure does not really gives you opportunity to understand how array was typed. What you should do instead is to extract head ( first element) of array and check it's type. For example following code works for me:
List(1,2,3) match {
case (a:Int) :: tail => println("yep")
}
This work, although not very nice:
def x(y: Array[_]) = y match {
case a if a.isInstanceOf[Array[Double]] ||
a.isInstanceOf[Array[Float]] ||
a.isInstanceOf[Array[BigDecimal]] => "call z"
case _ => "show error"
}
Would have thought that pattern matching with "|" as below would do the trick. However, this gives pattern type is incompatible with expected type on Array[Float] and Array[BigDecimal]. It might be that matching of generic on this single case where it could work has not been given so much attention:
def x(y: Array[_ <: Any]) = y match {
case a # (_:Array[Double] | _:Array[Float] | _:Array[BigDecimal]) => "call z"
case a: Array[_] => "show error"
}
May be it helps a bit:
import reflect.runtime.universe._
object Tester {
def test[T: TypeTag](y: Array[T]) = y match {
case c: Array[_] if typeOf[T] <:< typeOf[AnyVal] => "hi"
case c: Array[_] => "oh"
}
}
scala> Tester.test(Array(1,2,3))
res0: String = hi
scala> Tester.test(Array(1.0,2.0,3.0))
res1: String = hi
scala> Tester.test(Array("a", "b", "c"))
res2: String = oh
You can obtain the class of array elements as follows (it will be null for non-array types): c.getClass.getComponentType. So you can write:
if (Set(classOf[Float], classOf[Double], classOf[BigDecimal]).contains(c.getClass.getComponentType)) {
// call z
} else {
// show error
}
Not particularly Scala'ish, though; I think #thoredge's answer is the best for that.
You could also check whether the Array is empty first and then if not, just pattern match on Array.head...something like:
def x(y: Array[_]) = {
y.isEmpty match {
case true => "error"
case false => y.head match {
case a:Double | a:BigInt => do whatever
case _ => "error"
}
}
}
I have a function that as a parameter takes an object and if it is of the correct type I need to access the last element in an Option[List[Int]]. I have a working solution but it seems clumsy. In the case that there are not any items in obj.listOfThings I will need to have i have the value 0. Is there a better way to achieve this?
val i = foo match {
case obj: Bar =>
obj.listOfInts match {
case Some(ints) =>
ints.last
case _ =>
0
}
case _ =>
0
}
Technically it could return an Option[Int]. I'm still pretty new to Scala and would like to learn better approaches to this sort of problems.
In your case initially it seems that what Ende Neu suggested is the right way to go:
val i = foo match {
case obj: Bar =>
obj.listOfInts.map(_.last /* This throws an exception when the list is empty*/).getOrElse(0)
case _ =>
0
}
But if you look into it you'll see that you have a bug in your code, in the case that that obj.listOfInts is Some(Nil), because in that case you get a NoSuchElementException for trying to call last on an empty List.
Try this code with foo = Bar(Some(Nil)) and see for yourself.
When you use Option[List] think very carefully if this is what you want.
Usually after some thinking you will scrap the Option and just stay with a List because the Option serves no purpose.
I worked with many developers who misuse Option[List] because of not understanding the similarities between Nil and None and usually the 'None' case ends up playing the same role as Some(Nil)
So you end up having to do this:
optionalList match {
case None => // do something
case Some(list) =>
list match {
case Nil => // do the same thing
case head::tail => // do other stuff
}
}
As you can see the None case and the Some(Nil) case are basically the same.
To fix your bug you should do:
case class Bar(listOfInts: Option[List[Int]])
val i = foo match {
case Bar(Some(list)) if list != Nil => list.last
case _ => 0
}
You probably want to use flatMap and lastOption here:
obj.listOfInts.flatMap(_.lastOption)
In case listOfInts is None, or it is Some(Nil), this will return None. Otherwise it will return the last element. If you want to return 0 instead of None, just use getOrElse:
obj.listOfInts.flatMap(_.lastOption).getOrElse(0)
If you wanted to use a match, you could do:
obj.listOfInts match {
case Some(list#(hd::tl)) => list.last
case _ => 0
}
Here, the hd::tl guarantees that list is not empty. Another option is use a conditional match:
obj.listOfInts match {
case Some(list) if list.nonEmpty => list.last
case _ => 0
}
Or to match the None and Some(Nil) cases first:
obj.listOfInts match {
case None | Some(Nil) => 0
case Some(list) => list.last
}
As suggested in the comments, I think the best way to go is:
val i = foo match {
case obj: Bar => obj.listOfInts.map(_.last).getOrElse(0)
case _ => 0
}
More concise way including the instanceof:
scala> case class B(is: Option[List[Int]])
defined class B
scala> def f(x: Any) = Option(x) collect { case b: B => b.is flatMap (_.lastOption) } flatten
f: (x: Any)Option[Int]
scala> f(B(Option(5 to 7 toList)))
res0: Option[Int] = Some(7)
or
scala> import PartialFunction.{ condOpt => when }
import PartialFunction.{condOpt=>when}
scala> def g(x: Any) = when(x) { case b: B => b.is flatMap (_.lastOption) } flatten
g: (x: Any)Option[Int]
scala> g(B(Option(5 to 7 toList)))
res1: Option[Int] = Some(7)
It's probably worth asking why you lost static type info, that you need to pattern match.
I want to print the value if the it's not an option, and print the value inside the option if it's option. How to get that? The following doesn't work
val a="test"
def b= a match {
case i:Some[_] => i.getOrElse("1")
case _#x=>x
}
Something like this I think:
val a: Any = "test"
def b[T] = a match {
case i: Option[T] => i.getOrElse("1")
case _#x=>x
}
First a must be some supertype you can match on, if you had a: String matching on options would not be possible because you would already know that it's a string, note also that you have to pass a type parameter for option.
val a:Any="test"
def b= a match {
case Some(i) => i
case None => "1"
case x=>x
}
I am trying to implement a method using a case statement, but the following code does not compile.
I am aware I can get this working by using a pattern match, but am curious as to why the case statement is incompatible as a direct implementation....
trait Calculation[Input, Result] {
def calculate(in: Input): Result
}
class CalculationImpl : Calculation[String, int] {
// missing parameter type for expanded function
// The argument types of an anonymous function must be fully known. (SLS 8.5)
def calculate = {
case "one" => 1
case "two" => 2
case s: String => 0
}
}
As a compromise, I could change the semantics of the trait so that calculate becomes a parameterless method which returns a Function1, rather than a method which takes an Input parameter and returns a Result. However, this is not ideal...
trait Calculation[Input, Result] {
def calculate: Input => Result // Works, but semantics have changed.
}
class CalculationImpl : Calculation[String, int] {
def calculate = {
case "one" => 1
case "two" => 2
case s: String => 0
}
}
(note: the above is pseudo-code - I have not tried compiling this exact code)
You just need to fix your syntax and it will work:
def calculate(s: String) = s match {
case "one" => 1
case "two" => 2
case s: String => 0
}
You can get closer to the original semantics and still cut the boilerplate by defining calculate as a function value:
trait Calculation[Input, Result] {
type F = Input => Result
val calculate: F
}
class CalculationImpl extends Calculation[String, Int] {
val calculate: F = {
case "one" => 1
case "two" => 2
case s: String => 0
}
}
What is the Scala's way to write the following code:
int i;
switch(i) {
case 1:
a();
break;
case 2:
case 15:
b();
c();
break;
default: foo()
}
I.e. what is the idiomatic way of executing the same piece of code based on multiple case values?
i match {
case 1 => a
case 2 =>
case 15 => { b
c }
case _ => foo
}
Doesn't quite seem do the trick, since Scala evaluates the match value based on the first matching case, i.e. if i=2 the code will return nothing.
Thanks for help!
According to this conversation there is no fallthrough, but you can make use of |.
This should do the trick:
i match {
case 1 => a
case 2 | 15 => b
c
case _ => foo
}
Case statements can actually include additional logic guards using a standard if statement. So you could do something like:
i match {
case x if x == 1 => a
case x if (x == 2 | x == 15) => b; c;
case _ => foo
}
The matching guards can be any boolean function or composition of functions, so it gives it a lot more power than the standard switch statement in Java.
While not applicable here, for more complex problems you can 'fallthrough' in a sense using the andThen function on partial functions.
def do_function_a() { println("a"); }
def do_function_b() { println("b"); }
val run_function:PartialFunction[String, String] = {
case "a" => do_function_a(); "b"
case "b" => do_function_b(); "c"
}
(run_function andThen run_function)("a") // a\nb
If you are dealing with actual classes (instead of strings or ints), you need _: before each class to make them into a pattern before joining them with |.
sealed trait ShipCondition
case class ShipOnFire() extends ShipCondition
case class FoodSucks() extends ShipCondition
case class MateySnoresTooLoud() extends ShipCondition
case class Ok() extends ShipCondition
val condition = ShipOnFire()
def checkCondition(cond: ShipCondition): Unit = {
cond match {
case c # (_: ShipOnFire | _: FoodSucks) => println("Abandon Ship!") // can also use `c` for something. It has the type ShipCondition
case (_: MateySnoresTooLoud | _: Ok) => println("Deal with it!")
}
}
checkCondition(condition) // Abandon Ship!
You get nice exhaustive checking too! Note that you cannot do case class destructuring when using alternative pattern matching (e.g. case (MateySnoresTooLoud(str) | _: Ok) => will fail to compile.