在元组数组中求和值

时间:2014-06-10 21:46:58

标签: scala

使用下面的代码我试图将Double值相加

val v: List[(String, Array[((String, String), Double)])] = List( ("a" , Array((("a" , "b") , 1.0) , (("a" , "c") , 2.0) , (("a" , "d") , 3.0) , (("b" , "c") , 1.0) , (("b" , "d") , 4.0) , (("c" , "d") , 3.0))) )

def sum(xs: Array[((String, String), Double)]): Double = {

  @scala.annotation.tailrec
  def inner( xs:Array[((String, String), Double)] , accum: Double) : Double = {
    xs match {
      case x :: tail => inner(tail, accum + x._2)
      case Nil => accum
    }
  }
  inner(xs, 0)

}

但错误:

Multiple markers at this line - constructor cannot be instantiated to expected type; found : 
 scala.collection.immutable.::[B] required: Array[((String, String), Double)] - not found: value tail - constructor 
 cannot be instantiated to expected type; found : scala.collection.immutable.::[B] required: Array[((String, String), 
 Double)] - not found: value x

被抛出。

我的逻辑不正确吗?

2 个答案:

答案 0 :(得分:2)

::Nil是列表构造函数,因此您无法使用它们来匹配数组。可以在Arrays上匹配,尽管在这种情况下效率非常低,因为你需要在递归调用之间继续构造中间数组:

def sum(xs: Array[((String, String), Double)]): Double = {

  @scala.annotation.tailrec
  def inner( xs:Array[((String, String), Double)], accum: Double) : Double = {
    xs match {
      case Array(x, tail@_*) => inner(tail.toArray, accum + x._2)
      case Array() => accum
    }
  }
  inner(xs, 0)
}

请注意一个更简单的解决方案:

v.flatMap(_._2.map(_._2)).sum

您可以使用视图来阻止创建不必要的中间集合:

v.view.flatMap(_._2.view.map(_._2)).sum

答案 1 :(得分:0)

不是将Array转换为List并使用递归模式匹配,而是使用这种迭代方法:

val v: List[(String, Array[((String, String), Double)])] = List( ("a" , Array((("a" , "b") , 1.0) , (("a" , "c") , 2.0) , (("a" , "d") , 3.0) , (("b" , "c") , 1.0) , (("b" , "d") , 4.0) , (("c" , "d") , 3.0))) )
                                                  //> v  : List[(String, Array[((String, String), Double)])] = List((a,Array(((a,b
                                                  //| ),1.0), ((a,c),2.0), ((a,d),3.0), ((b,c),1.0), ((b,d),4.0), ((c,d),3.0))))

def sum(xs: Array[((String, String), Double)]): Double = {

  var sum = 0.0
    for(x <- xs){
      sum = sum + x._2
    }

  sum
}                                                 //> sum: (xs: Array[((String, String), Double)])Double

sum(v(0)._2)