Home > Software engineering >  Is there a better functional method to operate on Map[String,List[Int]]
Is there a better functional method to operate on Map[String,List[Int]]

Time:12-06

I'm fairly new to scala and functional programming, and I'm working on a project where I have grocery prices in 30 days and want to apply some analysis over the data that I have.

The data is saved as map(string, List[Int])

What I'm trying to do is to get the lowest and highest price for each item, I did it like this and then I have another function that loops over the returned Map and prints it.

def f(): Map[String,List[Int]] = {
    var result= Map.empty[String, List[Int]]
    for ((k,v) <- data){
      var low = v.min
      var high = v.max
      result = (k -> List(low,high));
    }
    result
  }

I think this is not the most functional method to do it, can anyone elaborate if there is a way to iterate over the data and return the result without creating an empty map?

CodePudding user response:

The computation does not depend on the keys in any way, so there is no reason to introduce the ks anywhere, it's just distracting from the main goal. Just map the values:

data.view.mapValues(v => (v.min, v.max)).toMap

Also, your signature f() doesn't tell anything useful. How do you know what it's doing? If you deleted the body of that function, and were given only "f()", would you be able to unambiguously reconstruct the body? Would the GPT be able to reconstruct the body? Probably not.

Ideally, the signature should be precise enough so you never need to dig into the implementation bodies (and also that you don't actually have to write them). Here is a possible improvement:

def priceRanges(itemsToPrices: Map[String, List[Int]]): Map[String, (Int, Int)] =
  itemsToPrices.view.mapValues(v => (v.min, v.max)).toMap

CodePudding user response:

There are several ways to achieve this. I think one key aspect is readability, so while the following can be done as a pure one-liner, I think this could be a viable and readable solution:

data.map { case (k, v) =>
  k -> Seq(v.min, v.max)
}

Feel free to shorten it if you like.

This would also work, but it may be less readable for someone not used to functional programming.

data.map(kv => kv._1 -> Seq(kv._2.min, kv._2.max))

Another thing you may want to consider: There is nothing that protects the List/Seq in the result type from containing more than two elements. You may want to use a tuple or create a custom type for it.

  • Related