Replacing while loop with idiomatic functional style - scala

Below code demonstrates two methods of summing a value where the termination condition is if the value reaches 5 :
object ob extends App {
def withoutRecursion = {
var currentTotal = 0.0;
while(5 > currentTotal){
currentTotal = currentTotal + scala.util.Random.nextFloat
println(currentTotal);
}
}
def withRecursion = {
var currentTotal = 0.0;
def whileLoop(cond : =>Boolean)(block : =>Unit) : Unit =
if(cond) {
block
whileLoop(cond)(block)
}
whileLoop(5 > currentTotal) {
currentTotal = currentTotal + scala.util.Random.nextFloat
println(currentTotal);
}
}
}
Is the withRecursion method the idiomatic method of replacing a while loop with a functional programming style in this case ?

Not really. In your examples you are still using a var to collect the intermediate results. That's not very FP.
One (of many) options is to create an infinite, but lazy, Stream to repeat the necessary calculations. Then if you want all the intermediate values you takeWhile(), or if you want just the end result you dropWhile().
Example:
Stream.iterate(0F)(_ + util.Random.nextFloat).takeWhile(_ < 5)
This creates a finite Stream with all the values from 0.0 to the largest sum less than 5.
On the other hand ...
Stream.iterate(0F)(_ + util.Random.nextFloat).dropWhile(_ < 5).head
... this will give you the first result greater than 5.

Related

How to speed up this Scala solution for an easy Leetcode problem?

I solved easy Leetcode problem Ransom Note in Scala like this :
def canConstruct(ransomNote: String, magazine: String): Boolean = {
val magazineChars = magazine.toSeq.groupBy(identity).mapValues(_.size)
val ransomChars = ransomNote.toSeq.groupBy(identity).mapValues(_.size)
ransomChars.forall { case (c, num) => magazineChars.getOrElse(c, 0) >= num }
}
This solution is Ok but slower than other accepted solutions in Scala.
Now I wonder how to speed it up. How would you suggest optimize this solution ?
For performance purpose, you should use low level data structure (primitive type instead of object type, array of primitive type instead of List, Map, i.e.), and low level syntax (while instead of foreach loop, i.e.)
Here is my solution, which beats 90% ~ 100% (it's random), you can speed up it by replace foreach to while loop and replace forall to while loop too, but it's too tedious:
a slightly optimized version of the above solution:
def canConstruct(ransomNote: String, magazine: String): Boolean = {
if (magazine.length < ransomNote.length) {
false // if the magazine has fewer letters than the ransom note, then we definitely can't make the note
} else {
var i = 0
val counts = Array.ofDim[Int](26)
while (i < magazine.length) {
counts(magazine(i) - 'a') += 1
if (i < ransomNote.length) counts(ransomNote(i) - 'a') -= 1 // avoid the need for another loop for the ransom note letters
i += 1
}
var c = 0;
while (c < counts.length) {
if (counts(c) < 0) {
return false
}
c += 1
}
true
}
}
with the following results (after a few runs):

Is there any way to replace nested For loop with Higher order methods in scala

I am having a mutableList and want to take sum of all of its rows and replacing its rows with some other values based on some criteria. Code below is working fine for me but i want to ask is there any way to get rid of nested for loops as for loops slows down the performance. I want to use scala higher order methods instead of nested for loop. I tried flodLeft() higher order method to replace single for loop but can not implement to replace nested for loop
def func(nVect : Int , nDim : Int) : Unit = {
var Vector = MutableList.fill(nVect,nDimn)(math.random)
var V1Res =0.0
var V2Res =0.0
var V3Res =0.0
for(i<- 0 to nVect -1) {
for (j <- i +1 to nVect -1) {
var resultant = Vector(i).zip(Vector(j)).map{case (x,y) => x + y}
V1Res = choice(Vector(i))
V2Res = choice(Vector(j))
V3Res = choice(resultant)
if(V3Res > V1Res){
Vector(i) = res
}
if(V3Res > V2Res){
Vector(j) = res
}
}
}
}
There are no "for loops" in this code; the for statements are already converted to foreach calls by the compiler, so it is already using higher-order methods. These foreach calls could be written out explicitly, but it would make no difference to the performance.
Making the code compile and then cleaning it up gives this:
def func(nVect: Int, nDim: Int): Unit = {
val vector = Array.fill(nVect, nDim)(math.random)
for {
i <- 0 until nVect
j <- i + 1 until nVect
} {
val res = vector(i).zip(vector(j)).map { case (x, y) => x + y }
val v1Res = choice(vector(i))
val v2Res = choice(vector(j))
val v3Res = choice(res)
if (v3Res > v1Res) {
vector(i) = res
}
if (v3Res > v2Res) {
vector(j) = res
}
}
}
Note that using a single for does not make any difference to the result, it just looks better!
At this point it gets difficult to make further improvements. The only parallelism possible is with the inner map call, but vectorising this is almost certainly a better option. If choice is expensive then the results could be cached, but this cache needs to be updated when vector is updated.
If the choice could be done in a second pass after all the cross-sums have been calculated then it would be much more parallelisable, but clearly that would also change the results.

Not sure where this type error is coming from

Im trying to test my code and all I get is a type error. I'm new to scala but as far as I can tell the ide is pointing at a bracket.
I've taken my function out of a main function (not sure what the purpose of that is, new to object oriented programming.) and I've tooled arount with my declarations
class FirstObject {
def computeShippingCosts(weight: Double): Double = {
var init: Double = 5.0
var overW: Double = weight - 30.0
if (weight >= 30) {
var total: Double = init + (overW * .25)
} else {
var total: Double = 5.0
}
}
println(computeShippingCosts(31.0))
}
I would expect the result of the println to be 5.25 but nothing prints other than the error so I don't know what to do.
Firstly, don't use return in Scala, it can cause some very odd errors. The last value in the function will be the result so there is no need for return.
You are getting an error because the last value is val ... and a declaration does not return a value (or rather it has the value Unit, which is the Scala equivalent of void).
It is also a good idea to avoid if/else if there is a function that can do the same thing. In this case you can use max:
def computeShippingCosts(weight: Double): Double =
math.max(5, weight*.25 - 2.5)
I think this also expresses the logic better because it makes it clear that there is a computed cost with a minimum value. And this ensures that a heavier parcel is never cheaper than a lighter parcel, which is harder to guarantee with the original logic.
If you want to retain the original form of code, it looks like this:
def computeShippingCosts(weight: Double): Double = {
val init: Double = 5
val overW: Double = weight - 30.0
if (weight >= 30) {
init + (overW*.25)
} else {
5.0
}
}
Andrey gives an alternative version which is more meaningful if you view the calculation as a base cost with a excess for overweight items:
def computeShippingCosts(weight: Double): Double =
5 + 0.25*(weight - 30).max(0)

Subtyping in Scala

I created a class that extends to Counter and it keeps track of the additions and subtractions. im trying to call xs and then return the sum of times that the number goes up or down that were called on instance by xs, Its compiling but its failing.
class Counter {
private var n = 0
def increment () = { n = n + 1 }
def decrement () = { n = n - 1 }
def get () : Int = n
}
def x (xs : Counter => Unit) : Int = {
class foo extends Counter {
var count = 0
def incrementAndGet = {count += 1; count}
def decrementAndGet = {count -= 1; count}
}
val counter1 = new foo
xs(counter1)
counter1.incrementAndGet
counter1.decrementAndGet
}
Thanks everyone, I was actually able to pass it. I needed to create another variable that can keep track of my increments and decrements and then inside the def inc and def dec, i would add in to either add or subtract from count :)
I suggest that you have a look at the Java design patterns & best practices first. Your foo class does not really extend counter since it does not shadow or override anything. Moreover you should use a singleton (object counter...) to keep track of your additions & substractions. Good luck.

How can I change mutable incremental number to be functional

I have this code UniqueKeyGenerator, there is a mutable variable number to be incrementally added, because I want to make the generated value to be predictable, I wonder how can I change it to be value instead of variable
object UniqueKeyGenerator {
var number = 0
def generate(suiteClass: Class[_]): String = {
number = number + 1
suiteClass.getCanonicalName + "." + this.number
}
}
Many thanks in advance
If you're just trying to express this with a val instead of a var, you could use an Iterator.
object UniqueKeyGenerator {
val numbers = Iterator.iterate(0)(_ + 1)
def generate(suiteClass: Class[_]): String =
s"${suiteClass.getCanonicalName}.${numbers.next()}"
}
Otherwise, I'm not sure what you're asking - maybe provide some more context?
If you have all of the inputs up front, then you can write something like this:
Seq(classOf[String], classOf[Int], classOf[String]).zipWithIndex
.map({ case (suiteClass, i) => s"${suiteClass.getCanonicalName}.$i" })
// res: List(java.lang.String.0, int.1, java.lang.String.2)
Aside from an Iterator you can also use a closure, for example if the id you want to generate is not just the next natural number, but a result of a more complex expression.
val nextId = {
var id = 0
() => {
id = id + 1 // change it to something more complex if you like
id
}
}
The "id" here is still a variable, but it is not accessible from the outside. The only way you can use it is by calling nextId:
def generate(suiteClass: Class[_]): String = {
suiteClass.getCanonicalName + "." + nextId()
}