Scala:从元组数组/RDD中获取第n个元素的总和

标签 scala collections functional-programming

我有一个数组 tuple像这样:

val a = Array((1,2,3), (2,3,4))

我想为如下方法编写一个通用方法:
def sum2nd(aa: Array[(Int, Int, Int)]) = {
      aa.map { a => a._2 }.sum
      }

所以我正在寻找一种方法,例如:
def sumNth(aa: Array[(Int, Int, Int)], n: Int)

最佳答案

有几种方法可以解决这个问题。最简单的就是使用productElement :

def unsafeSumNth[P <: Product](xs: Seq[P], n: Int): Int =
  xs.map(_.productElement(n).asInstanceOf[Int]).sum

然后(注意索引从零开始,所以 n = 1 给了我们第二个元素):
scala> val a = Array((1, 2, 3), (2, 3, 4))
a: Array[(Int, Int, Int)] = Array((1,2,3), (2,3,4))

scala> unsafeSumNth(a, 1)
res0: Int = 5

但是,此实现可能会以两种不同的方式在运行时崩溃:
scala> unsafeSumNth(List((1, 2), (2, 3)), 3)
java.lang.IndexOutOfBoundsException: 3
  at ...

scala> unsafeSumNth(List((1, "a"), (2, "b")), 1)
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
  at ...

即,如果元组没有足够的元素,或者您要求的元素不是 Int .

您可以编写一个不会在运行时崩溃的版本:
import scala.util.Try

def saferSumNth[P <: Product](xs: Seq[P], n: Int): Try[Int] = Try(
  xs.map(_.productElement(n).asInstanceOf[Int]).sum
)

进而:
scala> saferSumNth(a, 1)
res4: scala.util.Try[Int] = Success(5)

scala> saferSumNth(List((1, 2), (2, 3)), 3)
res5: scala.util.Try[Int] = Failure(java.lang.IndexOutOfBoundsException: 3)

scala> saferSumNth(List((1, "a"), (2, "b")), 1)
res6: scala.util.Try[Int] = Failure(java.lang.ClassCastException: ...

这是一个改进,因为它迫使调用者解决失败的可能性,但它也有点烦人,因为它迫使调用者解决失败的可能性。

如果您愿意使用 Shapeless你可以两全其美:
import shapeless._, shapeless.ops.tuple.At

def sumNth[P <: Product](xs: Seq[P], n: Nat)(implicit
  atN: At.Aux[P, n.N, Int]
): Int = xs.map(p => atN(p)).sum

进而:
scala> sumNth(a, 1)
res7: Int = 5

但坏的甚至不编译:
scala> sumNth(List((1, 2), (2, 3)), 3)
<console>:17: error: could not find implicit value for parameter atN: ...

但是,这仍然不完美,因为这意味着第二个参数必须是文字数字(因为它需要在编译时知道):
scala> val x = 1
x: Int = 1

scala> sumNth(a, x)
<console>:19: error: Expression x does not evaluate to a non-negative Int literal
       sumNth(a, x)
                 ^

不过,在许多情况下,这不是问题。

总结:如果您愿意为合理的代码崩溃您的程序承担责任,请使用 productElement .如果你想要更多的安全(以一些不便为代价),使用 productElementTry .如果您想要编译时安全(但有一些限制),请使用 Shapeless。

关于Scala:从元组数组/RDD中获取第n个元素的总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35091354/

相关文章:

java - 如何为 SBT 设置 Java 版本

Scala "update"不可变对象(immutable对象)最佳实践

javascript - 使用 mongodb 进行拉动刷新和无限集合加载

javascript - 将方法转换为以此为第一个参数的函数的函数

lambda - F# 在字符串数组上使用 List.map

scala - Scala 的 Netbeans 类型信息

scala - 错误 : value is not a member of object using Scala on the shell

php - 如何使用foreach遍历两个相同长度的集合

java - 从方法调用返回时模拟和处理 Map.Entry

Java如何使用可变参数方法和泛型返回类型实现接口(interface)