I am new to Scala and i am trying to create a function that calculates the amount a certain object appears in a sequence. So in this case we have a sequence with 1 Hippo and 3 Tigers in it. I want the amount of Tigers in the sequence. So the outcome of the function amountOfTigers should be an integer: 3. I want to make use of pattern matching and recursion to solve this. But i dont really know how to do this.
sealed trait Animal
case class Hippo(name: String, age: Int) extends Animal
case class Tiger(name: String, age: Int) extends Animal
def amountOfTigers(animals: Seq[Animal]): Int = animals match {
case head +: tail => if (head.isInstanceOf[Tiger]) println(head); amountOfTigers(tail)
}
val data = Seq[Animal](
Hippo("Mino", 4),
Tiger("Justin", 1),
Tiger("Jason", 20),
Tiger("Sloop", 10)
)
amountOfTigers(data)
println is used for testing purposes.
The output i am getting right now is:
Tiger(Justin,1)
Tiger(Jason,20)
Tiger(Sloop,10)
I want as a result the amount of Tigers in a sequence. So in this case its 3.
If you want to avoid recursion (which I personally suggest in this case - cause it's just an ordinary array of data), I suggest you use a loop, this way:
def amountOfTigers(animals: Seq[Animal]): Int = animals.count(_.isInstanceOf[Tiger])
If you insist using recursion, I suggest using #tailrec as Christian hinted:
def amountOfTigersRec(animals: Seq[Animal]): Int = {
#tailrec
def rec_fun(tail: Seq[Animal], count: Int): Int = tail match {
case Tiger(_, _) +: tail => rec_fun(tail, count + 1)
case _ +: tail => rec_fun(tail, count)
case Nil => count
}
rec_fun(animals, 0)
}
This is an example:
sealed trait Animal
case class Hippo(name: String, age: Int) extends Animal
case class Tiger(name: String, age: Int) extends Animal
def amountOfTigers(animals: Seq[Animal]): Int = animals match {
case Seq() => 0
case Tiger(_, _) +: tail => amountOfTigers(tail) + 1
case head +: tail => amountOfTigers(tail)
}
val data = Seq[Animal](
Hippo("Mino", 4),
Tiger("Justin", 1),
Tiger("Jason", 20),
Tiger("Sloop", 10)
)
print(amountOfTigers(data))
Things you might want to check out:
How to pattern match in Scala: https://docs.scala-lang.org/tour/pattern-matching.html as you rarely use isInstanceOf in Scala
For recursive functions, usually you start with thinking about the trivial case. Here: An empty seq has zero tigers.
Note that this example isn't very efficient, as it isn't tail recursive. Tail recursion is optimized into a loop by the Scala compiler. See e.g. https://www.geeksforgeeks.org/tail-recursion-in-scala/ for more details about this.
Related
I am new to Scala and I am having to provide values extracted from an object/case class into a Seq. I was wondering whether there would be any generic way of extracting values of an object into Seq of those values in order?
Convert the following:
case class Customer(name: Option[String], age: Int)
val customer = Customer(Some("John"), 24)
into:
val values = Seq("John", 24)
case class extends Product class and it provides such method:
case class Person(age:Int, name:String, lastName:Option[String])
def seq(p:Product) = p.productIterator.toList
val s:Seq[Any] = seq(Person(100, "Albert", Some("Einstain")))
println(s) //List(100, Albert, Some(Einstain))
https://scalafiddle.io/sf/oD7qk8u/0
Problem is that you will get untyped list/array from it. Most of the time it is not optimal way of doing things, and you should always prefer statically typed solutions.
Scala 3 (Dotty) might give us HList out-of-the-box which is a way of getting product's values without loosing type information. Given val picard = Customer(Some("Picard"), 75) consider the difference between
val l: List[Any] = picard.productIterator.toList
l(1)
// val res0: Any = 75
and
val hl: (Option[String], Int) = Tuple.fromProductTyped(picard)
hl(1)
// val res1: Int = 75
Note how res1 did not loose type information.
Informally, it might help to think of an HList as making a case class more generic by dropping its name whilst retaining its fields, for example, whilst Person and Robot are two separate models
Robot(name: Option[String], age: Int)
Person(name: Option[String], age: Int)
they could both represented by a common "HList" that looks something like
(_: Option[String], _: Int) // I dropped the names
If it's enough for you to have Seq[Any] you can use productIterator approach proposed by #Scalway. If I understood correctly you want also to unpack Option fields. But you haven't specified what to do with None case like Customer(None, 24).
val values: Seq[Any] = customer.productIterator.map {
case Some(x) => x
case x => x
}.toSeq // List(John, 24)
Statically typed solution would be to use heterogeneous collection e.g. HList
class Default[A](val value: A)
object Default {
implicit val int: Default[Int] = new Default(0)
implicit val string: Default[String] = new Default("")
//...
}
trait LowPriorityUnpackOption extends Poly1 {
implicit def default[A]: Case.Aux[A, A] = at(identity)
}
object unpackOption extends LowPriorityUnpackOption {
implicit def option[A](implicit default: Default[A]): Case.Aux[Option[A], A] = at {
case Some(a) => a
case None => default.value
}
}
val values: String :: Int :: HNil =
Generic[Customer].to(customer).map(unpackOption) // John :: 24 :: HNil
Generally it would be better to work with Option monadically rather than to unpack them.
Because I am defining an interpreter with a lot of variables, I am writing this:
type Context = Map[String, Int]
abstract class Expr
case class Let(varname: String, varvalue: Expr, body: Expr) extends Expr
case class Var(name: String) extends Expr
case class Plus(a: Expr, b: Expr) extends Expr
case class Num(i: Int) extends Expr
def eval(expr: Expr)(implicit ctx: Context): Int = expr match {
case Let(i, e, b) => eval(b)(ctx + (i -> eval(e)))
case Var(s) => ctx(s)
case Num(i) => i
case Plus(a, b) => eval(a) + eval(b)
}
For very long expressions this fails because of StackOverflowException, for expressions of the type:
Let("a", 1,
Let("b", Plus("a", "a"),
Let("c", Plus("b", "a"),
Let("d", 1, ... )
However, once the value of a variable is defined, I just need to call the evaluator again on the body of the Let, it seems to me that it should just do some kind of partial tail-recursion.
How is it possible to achieve partial tail recursion in Scala?
You want some way of getting tail-call optimizations on only some of the branches of eval. I don't think this is possible - the most Scala will do is accept a #tailrec annotation to a method as a whole and fail at compile time if it can't optimize the method into a loop.
However, making this iterative to take advantage of the the tail-call with the Let is pretty straight forward:
def eval(expr: Expr, ctx: Context): Int = {
// The expression/context pair we try to reduce at every loop iteration
var exprM = expr;
var ctxM = ctx;
while (true) {
expr match {
case Var(s) => return ctxM(s)
case Num(i) => return i
case Plus(a, b) => return eval(a,ctxM) + eval(b,ctxM)
case Let(i, e, b) => {
ctxM += i -> eval(e,ctxM). // Update ctxM
exprM = b // Update exprM
}
}
}
return 0; // unreachable, but Scala complains otherwise I'm not returning 'Int'
}
Note this won't solve the stack overflows due to long chains of Pluss - there really isn't much we can do with those because the recursive calls are not in tail position.
There was a time I thought Scala would make some #tailcall annotation to deal with this sort of thing, but I am not sure there is that much interest in such things anymore.
You should avoid using return in scala. In this scenario you could use a flag for the while control.
e.g.
var result = Option.empty[Int]
while (result.isEmpty) {
...
result = ctxM(s)
...
}
result
There are also other (IMO better) ways to go about this. For example https://typelevel.org/cats/datatypes/freemonad.html
I'm learning Scala by working the exercises from the book "Scala for the Impatient". Given the following way to model binary trees with case classes, one question asks to compute the sum of all elements in the leaves.
sealed abstract class BinaryTree
case class Leaf(value: Int) extends BinaryTree
case class Node(left: BinaryTree, right: BinaryTree) extends BinaryTree
My solution is as follows and works as expected. However, I'm using a MutableList and because Scala favors immutability, I am wondering if there's a way to solve the problem using List?
def leafSum(tree: BinaryTree): Int = {
collectLeaves(tree) { MutableList[Int]() }.sum
}
private def collectLeaves(tree: BinaryTree)(leaves: MutableList[Int]): MutableList[Int] = tree match {
case Node(left, right) =>
collectLeaves(left)(leaves); collectLeaves(right)(leaves)
case Leaf(value) => leaves += value
}
Using a List is not a good idea for the reason that when you concatenate two lists, you will have to copy their content so an O(n) complexity operation each time you encounter a Node.
If you really want to do it with Lists, you could do it like this:
def leafSum(tree: BinaryTree): Int = {
collectLeaves(tree).sum
}
private def collectLeaves(tree: BinaryTree): List[Int] = tree match {
case Node(left, right) => collectLeaves(left) ::: collectLeaves(right)
case Leaf(value) => List(value)
}
although in my opinion it's better to compute directly the sum as you don't need to store the values in the leaves:
def sum(tree: BinaryTree): Int = tree match {
case Node(left, right) => sum(left) + sum(right)
case Leaf(value) => value
}
Here's a recursive approach that doesn't use a helper method that I think is fairly elegant. Note it's not tail recursive and will run out of memory for large inputs.
def leafSum(tree: BinaryTree): Int = tree match{
case leaf:Leaf => leaf.value
case node:Node => leafSum(node.left) + leafSum(node.right)
}
I have a case class covariant on the type of one of its member variables, which is constrained to be of a particular type:
case class MyCount[+T <: Identifier](
id: T,
count: Long,
)
Identifier is a sealed trait with two concrete implementations though I don't believe that this matters for the question:
sealed trait Identifier
case class IdentifierFoo(...) implements Identifier
case class IdentifierBar(...) implements Identifier
Given a collection of MyCount[Identifier] I want to:
Extract all MyCount[IdentifierFoo]
Have the resulting collection have a type SomeCollection[MyCount[IdentifierFoo]]
The obvious (to me) way of doing it would be as follows:
src.collect { case countFoo: MyCount[IdentifierFoo] => countFoo }
However, this fails because the type of Count cannot be checked accurately at runtime due to type erasure: the result (incorrectly) gets all Counts. I've ended up doing something quite hairy looking:
src.collect { count =>
count.id match { case IdentifierFoo => {
count match {case countFoo: MyCount[IdentifierFoo] => countFoo }
} } }
This works but is ugly. I also tried matching the entire count as follows:
src.collect { case countFoo: MyCount[IdentifierFoo](_: IdentifierFoo, _) => countFoo }
...but this seems to not be valid in Scala 2.10, which is what I am constrained to. Is there a better way of doing what I want to do?
As #m-z mentions, you're better of matching on the structure than the types, but if you want the result to be of type List[MyCount[IdentifierFoo]], you have to cast the values:
val list: List[MyCount[Identifier]] = List(MyCount(IdentifierFoo(1), 2), MyCount(IdentifierBar(2), 3), MyCount(IdentifierBar(3), 4))
list.collect{ case countFoo # MyCount(_ : IdentifierFoo,_) => countFoo.asInstanceOf[MyCount[IdentifierFoo]]}
res0: List[MyCount[IdentifierFoo]] = List(MyCount(IdentifierFoo(1),2))
list.collect{ case countFoo # MyCount(_ : IdentifierBar,_) => countFoo.asInstanceOf[MyCount[IdentifierBar]]}
res1: List[MyCount[IdentifierBar]] = List(MyCount(IdentifierBar(2),3), MyCount(IdentifierBar(3),4))
Since you have extractors for IdentifierFoo and IdentifierBar and know their structure, you can use them. By using extractors, you aren't matching solely on the type, so we get around type erasure.
list.collect { case countFoo # MyCount(IdentifierFoo(_), _) => countFoo }
eg:
sealed trait Identifier
case class IdentifierFoo(id: Int) extends Identifier
case class IdentifierBar(id: Int) extends Identifier
case class MyCount[+T <: Identifier](id: T, count: Long)
val list = List(MyCount(IdentifierFoo(1), 2), MyCount(IdentifierBar(2), 3), MyCount(IdentifierBar(3), 4))
scala> list.collect { case countFoo # MyCount(IdentifierFoo(_), _) => countFoo }
res142: List[MyCount[Product with Serializable with Identifier]] = List(MyCount(IdentifierFoo(1),2))
scala> list.collect { case countFoo # MyCount(IdentifierBar(_), _) => countFoo }
res143: List[MyCount[Product with Serializable with Identifier]] = List(MyCount(IdentifierBar(2),3), MyCount(IdentifierBar(3),4))
What would be the best and/or easiest way to extract a value that I've saved in a case class?
take for example the following code:
abstract class Something
case class Foo(input: Int) extends Something
case class Bar(input: Double) extends Something
def someMethod(a: Something, b: Something) {
// code that extracts values goes here
}
someMethod(Foo(10), Foo(20))
someMethod(Bar(2.1), Bar(21.2))
how would I then go about getting the integer or the double itself out of a and b when I call the method like I did under its definition?
Note that both the parameters are used in the same equation
In case classes constructor arguments are vals, so just call:
a.input
b.input
You can also use extractor with the help of unapply method:
val Foo(val1) = a
val Bar(val2) = b
and then use val1 and val2
Update
Then you should use pattern matching on your value:
value match {
case Foo(val1) => val1
case Bar(val1) => val1
}
It works just like val Foo(val1) = a, with using generated unapply method (extractor) in your class, and it is also an expression, so you van assign the result to the variable
If you have multiple arguments just change PatMat construct according to the number of your parameters, in your case:
someMethod(a: Something, b: Something) = (a, b) match {
case (Foo(v1), Foo(v2)) => (v1, v2) // or any other logic with values
case (Foo(v1), Bar(v2)) => // logic for this case
... // logic for other cases
}
The more parameters the more cases you should provide, but you case blank cases if you don't need them
someMethod(a: Something, b: Something) = (a, b) match {
case (Foo(v1), Foo(v2)) => (v1, v2) // or any other logic with values
case _ =>
}
in this case all other cases will be ignored, not the best choice, cause the result type will be incorrect. And you also can black values
someMethod(a: Something, b: Something) = (a, b) match {
case (Foo(v1), _) => v1 // in such case you can work only with v1
... // logic for other cases
}
An alternative to pattern matching could be do redefine your classes like this:
trait Something[T]{
def input:T
}
case class Foo(input: Int) extends Something[Int]
case class Bar(input: Double) extends Something[Double]
Then, any instance of Something will expose the input property. The only potential downside is that it will be of a generic type when you access it.
The alternative approach
In addition to the direct solution of pattern matching in your method, I'll try to show a somewhat more convoluted, general and functional approach to this kind of situations. Still pattern matching is the most direct and simple answer!
If you can explicitly "certify" in your interface the input accessor, you can generalize how you work with the Something class.
In code this translates to
trait Something[T] {
def input: T
}
case class Foo(input: Int) extends Something[Int]
case class Bar(input: Double) extends Something[Double]
from here you can define how to "lift" any function you like to one that works over Somethings
Let's say you have methods that takes two inputs (e.g. Ints or Doubles) and you want to operate on such inputs within one of your case classes (i.e. Foo, Bar)
//this function lift your specific input method to one that takes Somethings
def liftSomething2[T, R](f: (T, T) => R): (Something[T], Something[T]) => R =
(a, b) => f(a.input, b.input)
Let's examine this a bit: it takes a function
(T, T) => R of 2 arguments of type T and a result R
and transforms it in a
(Something[T], Something[T]) => R which takes Somethings as arguments.
Examples
//lifts a function that sums ints
scala> val sumInts = liftSomething2[Int, Int](_ + _)
sumInts: (Something[Int], Something[Int]) => Int = <function2>
//lifts a function that multiplies ints
scala> val multInts = liftSomething2[Int, Int](_ * _)
multInts: (Something[Int], Something[Int]) => Int = <function2>
//lifts a function that divides doubles
scala> val divDbl = liftSomething2[Double, Double](_ / _)
divDbl: (Something[Double], Something[Double]) => Double = <function2>
//Now some test
scala> sumInts(Foo(1), Foo(2))
res2: Int = 3
scala> multInts(Foo(4), Foo(-3))
res3: Int = -12
scala> divDbl(Bar(20.0), Bar(3.0))
res4: Double = 6.666666666666667
//You can even complicate things a bit
scala> val stringApp = liftSomething2[Int, String](_.toString + _)
stringApp: (Something[Int], Something[Int]) => String = <function2>
scala> stringApp(Foo(1), Foo(2))
res5: String = 12
All the above examples lift functions of type (T,T) => R but the "lifting" can be made for all and any argument you need
//This takes three args of different types and returns another type
// the logic doesn't change
def liftSomething3[A,B,C,R](f: (A,B,C) => R): (Something[A], Something[B], Something[C]) => R =
(a,b,c) => f(a.input, b.input, c.input)
//sums to ints and divides by a double
scala> val sumDiv = liftSomething3[Int,Int,Double,Double]((i,j,d) => (i + j) / d)
sumDiv: (Something[Int], Something[Int], Something[Double]) => Double = <function3>
scala> sumDiv(Foo(5), Foo(30), Bar(4.2))
res7: Double = 8.333333333333332
more...
All we've seen so far should be somewhat related to category theory concepts like Applicative Functors and Comonads, but I'm no expert so I encourage you to search for yourself if you feel this sort of abstractions are useful and interesting.
In your example both the a and b have specific types: Foo and Bar respectively. That's why you can simply access their fields like so:
scala> a.input
res4: Int = 10
scala> b.input
res5: Double = 25.1
If however your value has type Something, then you'll need to pattern-match:
val input = somethingOfTypeSomething match {
case Foo(input) => input
case Bar(input) => input
}
The other answers have covered the basic scenario. There are useful variations to consider.
Constructor Pattern
As already answered there is:
value match {
case Foo(x) => x
...
}
Deep Matching
The constructor pattern also supports deep matching. For example, extract x within Bar within Foo which is 3 levels deep:
value match {
case Foo(y, Bar(x)) => x
...
}
Variable Binding
If the value you want to extract is an actual case class inside another case class you can use variable binding. E.g. to extract the whole Bar(x) into b:
value match {
case Foo(y, b # Bar(x)) => b
...
}
Programming in Scala by M. Odersky, Spoon and Venners has a great chapter on case classes and pattern matching which covers many other scenarios. Pattern matching is such a rich part of the language it would be a worthwhile investment.