如何将第一个列表中的每个元素添加到 Scala 中的相应列表?

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

所以我有一个列表:

    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))
    )

如何计算基本函数,例如:

对于每个列表的每个元素:

第一行

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

第二栏

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

第三栏

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

我目前卡在这里

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

这只打印每个嵌套列表的头部。我不知道如何获取嵌套元素的每个元素并进行上述计算

结果应该是这样的:

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

您可能希望从使用 transpose 方法开始,并从那里开始您需要的逻辑。以下是对示例数据调用 transpose 的结果:

scala> data.transpose.foreach(println)
List(Some(313.062468), Some(301.873641), Some(332.373186))
List(Some(27.847252), Some(42.884065), Some(53.509768))
List(Some(29.847252), Some(89.847252), Some(10.847252))

转置、展平和压缩

val list = data.transpose.flatMap(_.flatten)
list.tail zip list map { case (a, b) => (b - a)/b }

scala> val list = data.transpose.flatMap(_.flatten)
list: List[Double] = List(313.062468, 301.873641, 332.373186, 27.847252, 42.884065, 53.509768, 29.847252, 89.847252, 10.847252)

Scala REPL

scala> list.tail zip list map { case (a, b) => (b - a)/b }
res19: List[Double] = List(0.03573991820699504, -0.10103414428290529, 0.9162169116734945, -0.5399747522663995, -0.24777742035415723, 0.4422092803691468, -2.010235314125401, 0.8792700749489812)

不是一个巧妙的解决方案,但有效

data.zip(data.tail).map { case (alist, blist) => alist.flatten zip blist.flatten }.flatten.map { case (a, b) => (b - a)/b}

重要的代码行。

scala> data.zip(data.tail).map { case (alist, blist) => alist.flatten zip blist.flatten }.flatten
res4: List[(Double, Double)] = List((313.062468,301.873641), (27.847252,42.884065), (29.847252,89.847252), (301.873641,332.373186), (42.884065,53.509768), (89.847252,10.847252))

scala> data.zip(data.tail).map { case (alist, blist) => alist.flatten zip blist.flatten }.flatten.map { case (a, b) => (b - a)/b}
res5: List[Double] = List(-0.037064604126863805, 0.35063870460974256, 0.6678000569232768, 0.09176295286347183, 0.19857501531309202, -7.282950557431505)

Scala REPL

scala> 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))
     |     )
data: List[List[Some[Double]]] = 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)))

scala> data.zip(data.tail)
res0: List[(List[Some[Double]], List[Some[Double]])] = List((List(Some(313.062468), Some(27.847252), Some(29.847252)),List(Some(301.873641), Some(42.884065), Some(89.847252))), (List(Some(301.873641), Some(42.884065), Some(89.847252)),List(Some(332.373186), Some(53.509768), Some(10.847252))))

scala> data.zip(data.tail).map { case (alist, blist) => alist zip blist }
res1: List[List[(Some[Double], Some[Double])]] = List(List((Some(313.062468),Some(301.873641)), (Some(27.847252),Some(42.884065)), (Some(29.847252),Some(89.847252))), List((Some(301.873641),Some(332.373186)), (Some(42.884065),Some(53.509768)), (Some(89.847252),Some(10.847252))))

scala> data.zip(data.tail).map { case (alist, blist) => alist zip blist }.flatten
res2: List[(Some[Double], Some[Double])] = List((Some(313.062468),Some(301.873641)), (Some(27.847252),Some(42.884065)), (Some(29.847252),Some(89.847252)), (Some(301.873641),Some(332.373186)), (Some(42.884065),Some(53.509768)), (Some(89.847252),Some(10.847252)))

scala> data.zip(data.tail).map { case (alist, blist) => alist zip blist }.flatten
res3: List[(Some[Double], Some[Double])] = List((Some(313.062468),Some(301.873641)), (Some(27.847252),Some(42.884065)), (Some(29.847252),Some(89.847252)), (Some(301.873641),Some(332.373186)), (Some(42.884065),Some(53.509768)), (Some(89.847252),Some(10.847252)))

scala> data.zip(data.tail).map { case (alist, blist) => alist.flatten zip blist.flatten }.flatten
res4: List[(Double, Double)] = List((313.062468,301.873641), (27.847252,42.884065), (29.847252,89.847252), (301.873641,332.373186), (42.884065,53.509768), (89.847252,10.847252))

scala> data.zip(data.tail).map { case (alist, blist) => alist.flatten zip blist.flatten }.flatten.map { case (a, b) => (b - a)/b}
res5: List[Double] = List(-0.037064604126863805, 0.35063870460974256, 0.6678000569232768, 0.09176295286347183, 0.19857501531309202, -7.282950557431505)

转置列表,然后使用 .sliding(2) 获得元素的滚动 windows:

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)))

这个比其他的简单一点,没有使用transpose。它非常接近@pamu 的。我从@Marth 的回答中借用了diffPercent

data.sliding(2)
    .map{case List(a, b) => (a zip b).map {case (x,y) => diffPercent(x,y)}}
    .toList