Patrick Lafferty
Patrick Lafferty

Reputation: 537

Find the key in a map whose values satisfy a function

I am completely new to functional programming and I am working with scala. I am currently writing a program for my university coursework.

I have inputted the following map:

    val mapdata = Map(
    "SK1" -> List(9, 7, 2, 0, 7, 3, 7, 9, 1, 2, 8, 1, 9, 6, 5, 3, 2, 2, 7, 2, 8, 5, 4, 5, 1, 6, 5, 2, 4, 1),
    "SK2" -> List(0, 7, 6, 3, 3, 3, 1, 6, 9, 2, 9, 7, 8, 7, 3, 6, 3, 5, 5, 2, 9, 7, 3, 4, 6, 3, 4, 3, 4, 1),
    "SK3" -> List(8, 7, 1, 8, 0, 5, 8, 3, 5, 9, 7, 5, 4, 7, 9, 8, 1, 4, 6, 5, 6, 6, 3, 6, 8, 8, 7, 4, 0, 6),
    "SK4" -> List(2, 9, 5, 7, 0, 8, 6, 6, 7, 9, 0, 1, 3, 1, 6, 0, 0, 1, 3, 8, 5, 4, 0, 9, 7, 1, 4, 5, 2, 9),
    "SK5" -> List(2, 6, 8, 0, 3, 5, 5, 2, 5, 9, 4, 5, 3, 5, 7, 8, 8, 2, 5, 9, 3, 8, 6, 7, 8, 7, 4, 1, 2, 3),
    "SK6" -> List(2, 7, 5, 9, 1, 9, 8, 4, 1, 7, 3, 7, 0, 8, 4, 5, 9, 2, 4, 4, 8, 7, 9, 2, 2, 7, 9, 1, 6, 9),
    "SK7" -> List(6, 9, 5, 0, 0, 0, 0, 5, 8, 3, 8, 7, 1, 9, 6, 1, 5, 3, 4, 7, 9, 5, 5, 9, 1, 4, 4, 0, 2, 0),
    "SK8" -> List(2, 8, 8, 3, 1, 1, 0, 8, 5, 9, 0, 3, 1, 6, 8, 7, 9, 6, 7, 7, 0, 9, 5, 2, 5, 0, 2, 1, 8, 6),
    "SK9" -> List(7, 1, 8, 8, 4, 4, 2, 2, 7, 4, 0, 6, 9, 5, 5, 4, 9, 1, 8, 6, 3, 4, 8, 2, 7, 9, 7, 2, 6, 6)
    )

I am trying to output the key (stock symbol) which contains the maximum increase.

I have managed to find the maximum increase using the following code:

    def mostRecent(Is:List[Int]): Int = {
      if (Is.tail == Nil)
        return Is.head
      else
        mostRecent(Is.tail)
    }

    def penultimate(x: List[Int]): Int = x(x.length - 2)

    //this definition allow me to subtract the mostRecentValues and the penultimate values
    def subtractLast2(pen: Iterable[Int], last: Iterable[Int]): Iterable[Int] = {
         pen zip last map(x => x._1 - x._2)
    }

    //outputs a list with containing the last values 
    val MostRecentPrices = mapdata.values.map(x => mostRecent(x))

    //outputs a list with containing the second last values 
    val penultimatePrices = mapdata.values.map(x => penultimate(x))

    //determines the maximum increase 
    val maxIncrease = (subtractLast2(MostRecentPrices, penultimatePrices)).max


    //output the stock that has increased the most in the last day of the period
    println("MaxIncrease = " + maxIncrease)

I thought I was just about there until I found out I had to output the key that corresponds with the calculated maximum increase.

Was thinking of using getOrElse but really not sure as I am a beginner in scala and functional programming.

I hope this makes sense, please let me know if I need to clarify anything.

Thanks

Upvotes: 2

Views: 155

Answers (1)

adamwy
adamwy

Reputation: 1239

You can calculate two last elements by using pattern matching:

def mostRecent(is: List[Int]): (Int, Int) =
  is match {
    case a +: b +: Nil => (a, b)
    case head +: tail => mostRecent(tail)
    case Nil => throw new Exception("Can't calculate for an empty list")
  }

First it matches on a +: b +: Nil which extracts two first elements if tail is the end of the list. If it can't match this case, it tries to decompose the list as head +: tail, so it can call itself recursively for the tail. In case it was called with an empty list first it throws an exception.

Then, for every entry in mapdata you can calculate the two most recent elements, and subtract them:

val increases = 
  for {
    (k, v) <- mapdata
    (a, b) = mostRecent(v)
  } yield (k, b - a)

As a last step you can find maximum using maxBy method:

val max = increases.maxBy(_._2) 
max: (String, Int) = ("SK4", 7)

Upvotes: 3

Related Questions