将操作应用于Array的相应元素

时间:2014-07-16 20:38:11

标签: scala

我想总结列表的相应元素并将结果相乘,同时保持标签与数组元素相关联,这样

 ("a",Array((0.5,1.0),(0.667,2.0))) 

成为:

(a , (0.5 + 0.667) * (1.0 + 2.0))

这是我的代码,用于表示单个数组元素:

val data = Array(("a",Array((0.5,1.0),(0.667,2.0))), ("b",Array((0.6,2.0), (0.6,2.0))))
                                                  //> data  : Array[(String, Array[(Double, Double)])] = Array((a,Array((0.5,1.0),
                                                  //|  (0.667,2.0))), (b,Array((0.6,2.0), (0.6,2.0))))

  val v1 = (data(0)._1, data(0)._2.map(m => m._1).sum)
                                                  //> v1  : (String, Double) = (a,1.167)
  val v2 = (data(0)._1, data(0)._2.map(m => m._2).sum)
                                                  //> v2  : (String, Double) = (a,3.0)

  val total = (v1._1 , (v1._2 * v2._2))           //> total  : (String, Double) = (a,3.5010000000000003)

我只想将此函数应用于数组的所有元素,以便val" data"上面变成:

Map[(String, Double)] = ((a,3.5010000000000003),(b,4.8))

但是我不确定如何将上面的代码组合成一个映射所有数组元素的函数?

更新:内部数组可以是可变长度,因此这也是有效的:

val data = Array(("a",Array((0.5,1.0,2.0),(0.667,2.0,1.0))), ("b",Array((0.6,2.0), (0.6,2.0))))

3 个答案:

答案 0 :(得分:1)

模式匹配是你的朋友!您可以将它用于元组和数组。如果内部数组中总是有两个元素,则可以这样做:

val data = Array(("a",Array((0.5,1.0),(0.667,2.0))), ("b",Array((0.6,2.0), (0.6,2.0))))

data.map {
  case (s, Array((x1, x2), (x3, x4))) => s -> (x1 + x3) * (x2 + x4)
}
// Array[(String, Double)] = Array((a,3.5010000000000003), (b,4.8))

res6.toMap
// scala.collection.immutable.Map[String,Double] = Map(a -> 3.5010000000000003, b -> 4.8)

如果内部元素是可变长度的,你可以这样做(一个用于理解而不是显式地图):

for {
  (s, tuples) <- data
  sum1 = tuples.map(_._1).sum
  sum2 = tuples.map(_._2).sum
} yield s -> sum1 * sum2

请注意,尽管这是一个非常明确的解决方案,但它并不是最有效的解决方案,因为我们会迭代元组两次。你可以使用折叠,但它会更难阅读(对我来说无论如何。)

最后,请注意.sum将在空集合上产生零。如果这不是你想要的,你可以这样做:

val emptyDefault = 1.0 // Or whatever, depends on your use case

for {
  (s, tuples) <- data
  sum1 = tuples.map(_._1).reduceLeftOption(_ + _).getOrElse(emptyDefault)
  sum2 = tuples.map(_._2).reduceLeftOption(_ + _).getOrElse(emptyDefault)
} yield s -> sum1 * sum2

答案 1 :(得分:1)

您可以使用algebird数字库:

val data = Array(("a",Array((0.5,1.0),(0.667,2.0))), ("b",Array((0.6,2.0), (0.6,2.0))))

import com.twitter.algebird.Operators._

def sumAndProduct(a: Array[(Double, Double)]) = {
    val sums = a.reduceLeft((m, n) => m + n)
    sums._1 * sums._2
}

data.map{ case (x, y) => (x, sumAndProduct(y)) }  
// Array((a,3.5010000000000003), (b,4.8))

它也适用于可变大小的数组。

val data = Array(("a",Array((0.5,1.0))), ("b",Array((0.6,2.0), (0.6,2.0))))
// Array((a,0.5), (b,4.8))

答案 2 :(得分:0)

喜欢这个?你的阵列总是只有2对吗?

 val m = data map ({case (label,Array(a,b)) => (label, (a._1 + b._1) * (a._2 + b._2)) })
 m.toMap