blue-sky
blue-sky

Reputation: 53916

Generalise pattern matching on a sliding window over List

Below I've defined a function that splits a List into windows and applies a function to each sub list of size 4:

  def getValue(windowSize : Int, stepSize : Int, values: List[Double] , multiplier : Double) = {
    values.sliding(windowSize, stepSize).map({
      case List(v1, v2, v3, v4) =>
        (List(v1,v2,v3,v4) , (v2 >= (v1 * multiplier) && v3 >= (v2 * multiplier)), v4 > v3)
    }).toList
  }

  val data = List(5.0, 15.0, 45.0, 8.0, 5.0, 15.0, 45.0, 60.0)
  getValue(4,4,data , 2).foreach(println)

I want to be able to vary the size of the window of the List, for example, if I define a sliding window of size 5 and step size 5 then it should match as follows:

  case List(v1, v2, v3, v4, v5) =>
    (List(v1,v2,v3,v4,v5) , (v2 >= (v1 * multiplier) && v3 >= (v2 * multiplier)  && v4 >= (v3 * multiplier)), v5 > v4)

I could explicitly add a new case statement like:

  def getValue(windowSize : Int, stepSize : Int, values: List[Double] , multiplier : Double) = {
    if windowSize == 4 && stepSize == 4 {
    values.sliding(windowSize, stepSize).map({
      case List(v1, v2, v3, v4) =>
        (List(v1,v2,v3,v4) , (v2 >= (v1 * multiplier) && v3 >= (v2 * multiplier)), v4 > v3)
    }).toList
}
if windowSise == 5 && stepSize == 5 {
values.sliding(windowSize, stepSize).map({
      case List(v1, v2, v3, v4, v5) =>
        (List(v1,v2,v3,v4,v5) , (v2 >= (v1 * multiplier) && v3 >= (v2 * multiplier)  && v4 >= (v3 * multiplier)), v5 > v4)
  }).toList
  }

But then I need to add a new case each time I wish to vary the window size. Is there a more generic way to define this method using Scala, where I don't need a custom case pattern matching on the size of the list?

Upvotes: 1

Views: 135

Answers (1)

jwvh
jwvh

Reputation: 51271

Not terribly efficient but I think this does what you ask.

def getValue(groupSize: Int, values: List[Double], multiplier: Double) =
  values.grouped(groupSize).collect{
    case lst if lst.lengthIs == groupSize =>
      ( lst
      , lst.sliding(2).toList.init
           .forall{case List(a,b) => b >= (a*multiplier)}
      , lst.last > lst(groupSize-2)
      )
  }.toList

Upvotes: 3

Related Questions