0
votes

Below is code I use to filter over a sliding window of list data and each of the elements of data match a predicate then the data is filtered :

val data  : Map[String, List[Double]] = Map(
  "a" -> List(0.086, -0.398, -0.398, -0.312, 0.312, 0.312, 0.312, 0.312, 0.312, 0.312),
  "b" -> List(-0.119, -0.119, 1.007, 1.201, 1.201, 1.201, -1.201, 1.201, -1.201, -1.201)
)

def getChanges(f : Double => Boolean, data : Map[String, List[Double]], windowSize : Int) = {

  val result = data.map {
    case (key, value) => key -> value.sliding(windowSize).filter(_.forall(f)).toList
  }.filter {
    case (_, values) => values.nonEmpty
  }
   result
}


val threshold = 0
def f(percentChange : Double) = {
    percentChange > threshold
}

getChanges(f , data , 2).foreach(println)

prints :

(a,List(List(0.312, 0.312), List(0.312, 0.312), List(0.312, 0.312), List(0.312, 0.312), List(0.312, 0.312)))
(b,List(List(1.007, 1.201), List(1.201, 1.201), List(1.201, 1.201)))

this works as expected but is there a more idiomatic way to declare and call the function f ? The threshold value is set outside the function f which seems like a bad coding practice as threshold declared outside the f but I'm not sure if any alternatives exist. Also I may want to introduce more complicated filter logic such as :

val upperThreshold = 0
val lowerThreshold = -5
def f(percentChange : Double) = {
    percentChange > lowerThreshold and percentChange <= upperThreshold
}

But again, there are perhaps better ways to achieve this.

Scastie : https://scastie.scala-lang.org/PQLodmTPTvihEiYGgWAAvg

1
I am not sure what the question is? If you do not want to define the threshold inside the function, then do it, what is the problem? - Luis Miguel Mejía Suárez
What is the different between this question and your previous? - Tomer Shetah

1 Answers

2
votes

It would read better if you define getChange with a second parameter list:

def getChanges(data: Map[String, List[Double]], windowSize: Int)(f: Double => Boolean) = ???

Now, you can define your filter as a lambda (well, to be fair, you could make it a lambda with your original approach too, it just wouldn't look as pretty), and get rid of the threshold definition:

   getChanges(data , 2) { p => p >= -5 && p <= 0 }
     .foreach(println)