Search code examples
scalanested-listsfor-comprehensionscala-option

How can I add each element in first list with the corresponding list in Scala?


So I have a list so:

    var data = List(
      List(Some(313.062468), Some(27.847252), Some(29.847252)),
      List(Some(301.873641), Some(42.884065), Some(89.847252)),
      List(Some(332.373186), Some(53.509768), Some(10.847252))
    )

How can I compute basic function like:

For each element of each list:

First row

Some(301.873641) - Some(313.062468) / Some(313.062468)
Some(332.373186) - Some(301.873641) / Some(301.873641)

Second Column

Some(42.884065) - Some(27.847252) / Some(27.847252)
Some(53.509768) - Some(42.884065) / Some(42.884065)

Third Column

Some(89.847252) - Some(29.847252) / Some(29.847252)
Some(10.847252) - Some(89.847252) / Some(89.847252)

Im currently stuck here

data.map(_.head).foreach {
  case i => println(i)
}

This only prints the head of each nested list. I don't know how to get each element of the nested element and do the above calculation.

Result should be like this:

List(
  List(Some(-0.03573991820699504), Some(0.5399747522663995), Some(88.847252) )
  List(Some(0.10103414428290529), Some(0.24777742035415723), Some(9.847252) )
)

Solution

  • Transpose the list, then use .sliding(2) to get a rolling windows of the elements:

    scala> def diffPercent(o1: Option[Double], o2: Option[Double]) = (o1, o2) match {
             case (Some(d1), Some(d2)) => Some((d2 - d1) / d1)  // need to handle d1 == 0 too
             case _ => None
           }
    diffPercent: (o1: Option[Double], o2: Option[Double])Option[Double]
    
    // sample value before the final operation
    scala> data.transpose.map(_.sliding(2).toList) // .toList to show the values in REPL
    res13: List[List[List[Some[Double]]]] = List(List(List(Some(313.062468), Some(301.873641)), List(Some(301.873641), Some(332.373186))), ...)
    
    scala> data.transpose.map(_.sliding(2).map {
             case o1 :: o2 :: Nil => diffPercent(o1, o2)
             case _ => None // source has less than 2 elems
           }.toList).transpose  // transpose back the list
    res17: List[List[Option[Double]]] = List(List(Some(-0.03573991820699504), Some(0.5399747522663995), Some(2.010235314125401)), List(Some(0.10103414428290529), Some(0.24777742035415723), Some(-0.8792700749489812)))