1

I have written a few lines of code in Scala, but don't know how to make the same thing work with immutable variables (val). Any help will be much appreciated.

class Test {

  def process(input: Iterable[(Double, Int)]): (Double, Int) = {
    var maxPrice: Double = 0.0
    var maxVolume: Int = 0

    for ((price, volume) <- input) {
      if (price > maxPrice) {
        maxPrice = price
      }
      if (volume > maxVolume) {
        maxVolume = volume
      }
    }

    (maxPrice, maxVolume)
  }
}

Can anyone help me in converting all the var to val and making it more functional? Thanks in advance! :)

2 Answers 2

7

Use .foldLeft:

def process(input: Iterable[(Double, Int)]): (Double, Int) =
  input.foldLeft(0.0 -> 0) { case ((maxPrice, maxVolume), (price, volume)) =>
    val newPrice = if (maxPrice < price) price else maxPrice
    val newVolume = if (maxVolume < volume) volume else maxVolume
    newPrice -> newVolume
  }
Sign up to request clarification or add additional context in comments.

2 Comments

Wow Thanks @Mateusz
@SarfarazHussain Consider accepting the answer How does accepting an answer work?
2

For comparison here is a tail recursive solution

  def process(input: Iterable[(Double, Int)]): (Double, Int) = {
    @tailrec def loop(remaining: Iterable[(Double, Int)], maxPrice: Double, maxVolume: Int): (Double, Int) = {
      remaining match {
        case Nil => maxPrice -> maxVolume
        case (price, volume) :: tail =>
          val newPrice = if (maxPrice < price) price else maxPrice
          val newVolume = if (maxVolume < volume) volume else maxVolume
          loop(tail, newPrice, newVolume)
      }
    }
    loop(input, 0, 0)
  }

and corresponding jmh benchmark

@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
class So61366933 {
  def mario(input: Iterable[(Double, Int)]): (Double, Int) = {
    @tailrec def loop(remaining: Iterable[(Double, Int)], maxPrice: Double, maxVolume: Int): (Double, Int) = {
      remaining match {
        case Nil => maxPrice -> maxVolume
        case (price, volume) :: tail =>
          val newPrice = if (maxPrice < price) price else maxPrice
          val newVolume = if (maxVolume < volume) volume else maxVolume
          loop(tail, newPrice, newVolume)
      }
    }
    loop(input, 0, 0)
  }


  def mateusz(input: Iterable[(Double, Int)]): (Double, Int) =
    input.foldLeft(0.0 -> 0) { case ((maxPrice, maxVolume), (price, volume)) =>
      val newPrice = if (maxPrice < price) price else maxPrice
      val newVolume = if (maxVolume < volume) volume else maxVolume
      newPrice -> newVolume
    }

  import scala.util.Random._
  def arbTuple: (Double, Int) = nextDouble() -> nextInt()
  val input = List.fill(1000)(arbTuple)

  @Benchmark def foldLeft = mateusz(input)
  @Benchmark def tailRec = mario(input)
}

where

sbt "jmh:run -i 5 -wi 5 -f 2 -t 1 bench.So61366933"

outputs

[info] Benchmark             Mode  Cnt       Score      Error  Units
[info] So61366933.foldLeft  thrpt   10   80999.752 ± 2118.095  ops/s
[info] So61366933.tailRec   thrpt   10  259875.842 ± 7718.674  ops/s

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.