scala two variables if else condition - scala

How can I do this better in Scala?
def fooOutput(v1: Double, v2: Int): Int = {
if (v1 >= 9 & v2 >= 2) {
5
}
else if (v1 >= 8) {
4
}
else if (v1 >= 4) {
3
}
else {
2
}
}
I do not like this if else if else logic.
Can I use switch statement for two variables or maybe some better Scala functional approach?

You can move your condition into pattern guards, not sure that it will be much better though:
def fooOutput(v1: Double, v2: Int): Int = v1 match {
case _ if v1 >= 9 && v2 >= 2 => 5
case _ if v1 >= 8 => 4
case _ if v1 >= 4 => 3
case _ => 2
}

Related

scala: avoid a var while iterating and accumulating in a functional manner (no vars)

I need help to find the right Scala approach that will make this code more functional and less mutable.
def findMinTime(str: String, timeByCar: Int): Int = {
var myTime = timeByCar
var minTime = timeByCar
str.reverse.foreach { l =>
if (l == 'A') myTime += 3 else myTime -= 2
if (myTime < minTime) minTime = myTime
}
minTime
}
foldLeft is one way, useful when logic is simple and concise. But in general the go-to tool for this kind of tasks in scala is (tail) recursion:
`
def findMinTime(str: String, timeByCar: Int) = {
#tailrec
def loop(str: List[Char], minTime: Int, myTime: Int): Int = str match {
case Nil => minTime
case 'A' :: tail => loop(tail, myTime+3, minTime min myTime+3)
case _ :: tail => loop(tail, myTime -2, minTime min myTime-2)
}
loop(str.toList.reverse, timeByCar, timeByCar)
}
Here's a solution using foldLeft. We store the two variables we need to modify after each character (myTime and minTime) in a tuple as the accumulator.
def findMinTime(str: String, timeByCar: Int): Int = {
val (myTime, minTime) = str.reverse.foldLeft((timeByCar, timeByCar)) {
case ((myTime, minTime), l) =>
val newTime = if (l == 'A') myTime + 3 else myTime - 2
(newTime, newTime min minTime)
}
minTime
}

How to sort sequence of numeric data type in scala

I am newbie to scala and for practice I am trying to write a generic function that calculates median for sequence of integer or doubles.
Below is the snippet of the code :
implicit class trial[T](seq: Seq[T]) {
def median[T](implicit num: Fractional[T]):Double = {
import num._
seq.sorted match {
case x if x.length % 2 != 0 => x(x.length / 2).toDouble()
case x => (x(x.length / 2).toDouble() + x(x.length / 2 - 1).toDouble()) / 2
}
}
}
In the above code sorted function is not working saying implicit ordering can not be found.Can some one guide me on how can we sort the list of numerics in scala?
Edit ==>
After going through answers on this post I have changed my code(changed code is pasted below) and now this is working for Ints and Doubles,but now if in future If I have to support BigDecimals then what changes will I have to make?
implicit class GenericMedian[T](seq: Seq[T]) {
def median(implicit num: Numeric[T]) = {
import num._
val medianPosition = seq.length / 2
seq.sortWith(num.gt) match {
case x if x.length % 2 != 0 => x(medianPosition)
case x => (x(medianPosition).toDouble() + x(medianPosition - 1).toDouble()) / 2
}
}
}
The following uses Numeric typeclass to handle both integers and doubles
implicit class MedianSeq[T](seq: Seq[T]) {
def median(implicit num: Numeric[T]): Option[Double] = {
val sorted = seq.sorted
val fractionalMidpoint: Double = sorted.size / 2.0
sorted.size match {
case x if x < 2 => None
case x if x == 2 => Some(num.toDouble(num.plus(seq(0), seq(1))) / 2)
case x =>
if (fractionalMidpoint % 2 != 0.0) {
Some(num.toDouble(sorted(fractionalMidpoint.toInt)))
} else {
val a = sorted(fractionalMidpoint.toInt - 1)
val b = sorted(fractionalMidpoint.toInt)
Some(num.toDouble(num.plus(a, b)) / 2)
}
}
}
}
which outputs
Seq(3,5,2,34,5,6,7,87,8).median == Some(6.0) // true
Seq(1,2,3,4).median == Some(2.5) // true
Seq(1.0,2.0,3.0,4.0).median == Some(2.5) // true
Seq(1,2).median == Some(1.5) // true
Seq(1,1).median == Some(1.0) // true
Seq(1).median == None // true
Note we use this definition of median when there are even number of elements:
When there are two middle numbers we average them.
hence Seq(1,2).median == Some(1.5)
This is working for me on Scala 2.13
implicit class trial[T](private val seq: Seq[T]) extends AnyVal {
def median(implicit num: Integral[T]): T = {
import num._
val sorted = seq.sorted
val length = sorted.length
val medianPosition = length / 2
if ((length % 2) == 0)
sorted(medianPosition)
else
(sorted(medianPosition) + sorted(medianPosition + 1)) / num.fromInt(2)
}
}
I forgot to mention that the only real problem with your code (at least in terms of compilation) is that since you are defining a new T type variable on the definition of the method. You can not sort the sequence with that implicits, because for the compiler those were two different types.

StackOverflowError for coin change in Scala?

I'm writing a recursive function for the Coin (change) problem in Scala.
My implementation breaks with StackOverflowError and I can't figure out why it happens.
Exception in thread "main" java.lang.StackOverflowError
at scala.collection.immutable.$colon$colon.tail(List.scala:358)
at scala.collection.immutable.$colon$colon.tail(List.scala:356)
at recfun.Main$.recurs$1(Main.scala:58) // repeat this line over and over
this is my call:
println(countChange(20, List(1,5,10)))
this is my definition:
def countChange(money: Int, coins: List[Int]): Int = {
def recurs(money: Int, coins: List[Int], combos: Int): Int =
{
if (coins.isEmpty)
combos
else if (money==0)
combos + 1
else
recurs(money,coins.tail,combos+1) + recurs(money-coins.head,coins,combos+1)
}
recurs(money, coins, 0)
}
Edit: I just added the else if statement in the mix:
else if(money<0)
combos
it got rid of the error but my output is 1500 something :( what is wrong with my logic?
The first solution in the accepted answer has a redundant last parameter as noted by Paaro so I wanted to get rid of it. The second solution uses map which I wanted to avoid since it wasn't covered yet in the Week 1 or the Scala course I assume you're taking. Also, the second solution, as rightly noted by the author, would be way slower, unless it uses some memoization. Finally, Paaro's solution seems to have an unnecessary nested function.
So here's what I ended up with:
def countChange(money: Int, coins: List[Int]): Int =
if (money < 0)
0
else if (coins.isEmpty)
if (money == 0) 1 else 0
else
countChange(money, coins.tail) + countChange(money - coins.head, coins)
There is no need for braces here, as you can see.
I wonder if it could be further simplified.
Here is the correct solution based on your codes:
def countChange(money: Int, coins: List[Int]): Int = {
def recurs(m: Int, cs: List[Int], cnt: Int): Int =
if(m < 0) cnt //Not a change, keep cnt
else if(cs.isEmpty) {
if(m == 0) cnt + 1 else cnt // plus cnt if find a change
}
else recurs(m, cs.tail, cnt) + recurs(m-cs.head, cs, cnt)
recurs(money, coins, 0)
}
Anyway, there is a short solution(But not efficient, you can cache the middle result to make it efficient.)
def countChange(m: Int, cs: List[Int]): Int = cs match {
case Nil => if(m == 0) 1 else 0
case c::rs => (0 to m/c) map (k => countChange(m-k*c,rs)) sum
}
One can omit the cnt parameter, which is, in fact, never accumulated. The recurs function always returns either 0 or 1, so the optimized algorithm would be:
def countChange(money: Int, coins: List[Int]): Int = {
def recurs(m: Int, cs: List[Int]): Int =
if(m < 0) 0 //Not a change, return 0
else if(cs.isEmpty) {
if(m == 0) 1 else 0 // 1 if change found, otherwise 0
}
else recurs(m, cs.tail) + recurs(m-cs.head, cs)
if(money>0) recurs(money, coins) else 0
}
The #Eastsun solution is good but it fails when money=0 due to it returns 1 instead of 0, but you can fix it easily:
def countChange(money: Int, coins: List[Int]): Int = {
def recurs(m: Int, cs: List[Int], cnt: Int): Int =
if(m < 0) cnt //Not a change, keep cnt
else if(cs.isEmpty) {
if(m == 0) cnt + 1 else cnt // plus cnt if find a change
}
else recurs(m, cs.tail, cnt) + recurs(m-cs.head, cs, cnt)
if(money>0) recurs(money, coins, 0) else 0
}
here is a DP approach to reduce a lot of re-calculation in recursive approach
object DP {
implicit val possibleCoins = List(1, 5, 10, 25, 100)
import collection.mutable.Map
def countChange(amount: Int)(implicit possibleCoins: List[Int]) = {
val min = Map((1 to amount).map (_->Int.MaxValue): _*)
min(0) = 0
for {
i <- 1 to amount
coin <- possibleCoins
if coin <= i && min(i - coin) + 1 < min(i)
} min(i) = min(i-coin) + 1
min(amount)
}
def main(args: Array[String]) = println(countChange(97))
}
see DP from novice to advanced for algorithm
Idea from https://github.com/pathikrit/scalgos/blob/9e99f73b4241f42cc40a1fd890e72dbeda2df54f/src/main/scala/com/github/pathikrit/scalgos/DynamicProgramming.scala#L44
case class Memo[K,I,O](f: I => O)(implicit i2k:I=>K ) extends (I => O) {
import scala.collection.mutable.{Map => Dict}
val cache = Dict.empty[K, O]
override def apply(x: I) = cache getOrElseUpdate (x, f(x))
}
def coinchange(s: List[Int], t: Int) = {
type DP = Memo[ (Int, Int), (List[Int], Int),Seq[Seq[Int]]]
implicit def encode(key: (List[Int], Int)):(Int,Int) = (key._1.length, key._2)
lazy val f: DP = Memo {
case (Nil, 0) => Seq(Nil)
case (Nil, _) => Nil
case (_, x) if x< 0 => Nil
case (a :: as, x) => f(a::as, x - a).map(_ :+ a) ++ f(as, x)
}
f(s, t)
}

Abuse of match?

Would you consider the following block of code match abuse and if so what's a more elegant way to do it without a big if-else-if block?
def sum(base: Int, xs: List[Int]): Int = {
base match {
case 0 => 1
case _ if (base < 0) => 0
case _ if (xs.isEmpty) => 0
case _ => xs.sum
}
}
Yes, this an abuse of match. You've basically just written a big if-else-if block, but in a more awkward form. What's wrong with if-statements?
I think it's much cleaner to just write this:
def countChange(money: Int, coins: List[Int]): Int = {
if(money == 0) 1
else if (money < 0) 0
else if (coins.isEmpty) 0
else countChange(money, coins.tail) + countChange(money - coins.head, coins)
}
If you want to stick with a match, you can move more of the checking into the match itself, so that it's actually doing something:
def countChange(money: Int, coins: List[Int]): Int = {
(money, coins) match {
case (0, _) => 1
case _ if (money < 0) => 0
case (_, Nil) => 0
case (_, coinsHead :: coinsTail) => countChange(money, coinsTail) + countChange(money - coinsHead, coins)
}
}
No. Why abuse? It's fairly readable IMO...
The problem I see is that money match ... is fairly arbitrary (you only use the direct pattern in the first case); a complete "abuse" would start like
() match {
case _ if (money == 0) => 1
...
So perhaps stick to if-else; you can combine the second and third condition (if( money < 0 || coins.isEmpty ) ...)
Also note that although you "know" in the end that coins is not empty and thus may "safely" call head and tail on it, this is a typical source of unexpected runtime errors. The advantage of coins match { case Nil => ...; case head :: tail => ...} is that you cannot make such a mistake.

coin change algorithm in scala using recursion

I am trying to program the coin change problem in Scala using recursion. The code that i have written is as follows.
def countChange(money: Int, coins: List[Int]): Int = {
def ways(change: List[Int], size: Int, capacity: Int): Int = {
if(capacity == 0) 1
if((capacity < 0) || (size <= 0)) 0
//println and readLine to check and control each recursive call.
println("calling ways(",change, change.length-1, capacity,") + ways(",change, change.length, capacity - change(change.length - 1),")")
readLine()
//
ways(change, change.length-1, capacity) + ways(change, change.length, capacity - change(change.length - 1))
}
ways(coins, coins.length, money)
}
On running the code, it does not terminate and keeps on calling the first recursive call. Where am I going wrong?
Nice and simple
def countChange(money: Int, coins: List[Int]): Int = {
if(money == 0)
1
else if(money > 0 && !coins.isEmpty)
countChange(money - coins.head, coins) + countChange(money, coins.tail)
else
0
}
Here is my implementation:
I have tested it and it works fine
def countChange(money: Int, coins: List[Int]): Int = {
def count(capacity: Int, changes: List[Int]): Int = {
if (capacity == 0)
1
else if (capacity < 0)
0
else if (changes.isEmpty && capacity >= 1)
0
else
count(capacity, changes.tail)
+ count(capacity - changes.head, changes)
}
count(money, coins.sortWith(_.compareTo(_) < 0))
}
Just another solution
def countChange(amount: Int, coins: List[Int]): Int = coins match {
case _ if amount == 0 => 1
case h :: t if amount > 0 => countChange(amount - h, h :: t) + countChange(amount, t)
case _ => 0
}
Simply stating a value does not make Scala return it; you either need an explicit return, or it has to be the last item stated. Thus:
if (capacity == 0) return 1
or
if (capacity == 0) 1
else if (...)
else { ... }
Hey I just thought it would be better to see not only the amount but also the list of them, so put on top of the above example like :
def moneyChanges(money: Int, coins: List[Int]) : Option[List[Seq[Int]]]= {
var listOfChange=List[Seq[Int]]()
def changeMoney(capacity: Int, changes: List[Int], listOfCoins: Option[Seq[Int]]): Int = {
if (capacity == 0) {
listOfChange = listOfCoins.get :: listOfChange
1
} else if (capacity < 0)
0
else if (changes.isEmpty && capacity >= 1)
0
else {
changeMoney(capacity, changes.tail, listOfCoins) +
changeMoney(capacity - changes.head, changes,
Some(changes.head +: listOfCoins.getOrElse(Seq())))
}
}
changeMoney(money, coins.sortWith(_.compareTo(_) < 0), None)
Some(listOfChange)
}
here is a DP approach to reduce a lot of re-calculation in recursive approach
object DP {
implicit val possibleCoins = List(1, 5, 10, 25, 100)
import collection.mutable.Map
def countChange(amount: Int)(implicit possibleCoins: List[Int]) = {
val min = Map((1 to amount).map (_->Int.MaxValue): _*)
min(0) = 0
for {
i <- 1 to amount
coin <- possibleCoins
if coin <= i && min(i - coin) + 1 < min(i)
} min(i) = min(i-coin) + 1
min(amount)
}
def main(args: Array[String]) = println(countChange(97))
}
see DP from novice to advanced for algorithm
Below code is similar to one of the above example except I am using match case instead of if else
def countChange(money: Int, coins: List[Int]): Int = {
def change(m: Int, coinList: List[Int], count: Int): Int =
m match {
case _ if m < 0 => count
case _ if coinList.isEmpty => {
m match {
case 0 => count + 1
case _ => count
}
}
case _ => change(m, coinList.tail, count) + change(m - coinList.head, coinList, count)
}
change(money, coins, 0)
}
Here is my code: It's not optimized but works on all test cases.
The idea is to subtract first coin of list from from money until it becomes 0. Once it becomes 0, it will return 1 which means one solution is possible. To add all solutions coming from different recursion I used foldLeft.
(iterating list using foldLeft, so first goes in 1, then again goes in recursion and iterate for (1, 2) list)
[4, (1, 2)].
/(1 as cn) \ (2 as cn)
[3, (1, 2)]. [2, (2)]
/(-1) \(-2) \
[2, (1, 2)]. [1, (2)]. [0, (2)]
/.(-1) \(-2)
[1, (1, 2)]. [0, (2)]
/. (-1) \(-2)
[0, (1, 2)]. [-1, (2)]
def countChange(money: Int, coins: List[Int]): Int = coins.foldLeft(0)((accum, cn) =>
(money, cn) match {
case (money, _) if money < 0 => 0
case (0, _) => 1
case (curr_money, curr_coin) =>
val (before_curr_coin, after_curr_coin) = coins.span(_ != curr_coin)
accum + countChange(curr_money - curr_coin, after_curr_coin)
})
This will handle the case where money is zero but not negative coins...
def countChange(money: Int, coins: List[Int]): Int = {
def loop(money: Int, coins: List[Int]): Int = {
if(money == 0) {
1
} else if(money > 0 && !coins.isEmpty) {
loop(money - coins.head, coins) + loop(money, coins.tail)
} else {
0
}
}
if(money == 0) {
0
} else {
loop(money: Int, coins: List[Int])
}
}