gpt4 book ai didi

Scala: Get sum of nth element from tuple array/RDD(Scala:从元组数组/RDD中获取第n个元素的总和)

转载 作者:bug小助手 更新时间:2023-10-28 09:56:10 25 4
gpt4 key购买 nike



I have a array of tuple like this:

我有一个这样的元组数组:



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


I want to write a generic method for a method like below:

我想为如下所示的方法编写泛型方法:



def sum2nd(aa: Array[(Int, Int, Int)]) = {
aa.map { a => a._2 }.sum
}


So what I am looking for a method like:

因此,我正在寻找一种方法,如:



def sumNth(aa: Array[(Int, Int, Int)], n: Int)

更多回答

Are the tuple elements always the same type?

元组元素总是相同的类型吗?

lets assume for simplicity, same type and tuple of same size

为简单起见,我们假设相同类型和相同大小的元组

If you want an indexed sequence (which is what you seem to want), use a datastructure that is an IndexedSequence! (e.g. List, Array, Vector). If you want to access element n for variable n, then Tuples are the wrong choice

如果您想要索引序列(这似乎就是您想要的),请使用IndexedSequence的数据结构!(例如,列表、数组、向量)。如果您想访问变量n的元素n,那么元组是错误的选择

优秀答案推荐

There are a few ways you can go about this. The simplest is to use productElement:

有几种方法可以做到这一点。最简单的方法是使用ProductElement:



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


And then (note that indexing starts at zero, so n = 1 gives us the second element):

然后(请注意,索引从零开始,因此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


This implementation can crash at runtime in two different ways, though:

不过,此实现在运行时可能会以两种不同的方式崩溃:



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


I.e., if the tuple doesn't have enough elements, or if the element you're asking for isn't an Int.

也就是说,如果元组没有足够的元素,或者如果您请求的元素不是Int。



You can write a version that doesn't crash at runtime:

您可以编写一个不会在运行时崩溃的版本:



import scala.util.Try

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


And then:

然后:



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: ...


This is an improvement, since it forces callers to address the possibility of failure, but it's also kind of annoying, since it forces callers to address the possibility of failure.

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



If you're willing to use Shapeless you can have the best of both worlds:

如果你愿意使用Shapless,你可以两全其美:



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


And then:

然后:



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


But the bad ones don't even compile:

但糟糕的版本甚至都不会编译:



scala> sumNth(List((1, 2), (2, 3)), 3)
<console>:17: error: could not find implicit value for parameter atN: ...


This still isn't perfect, though, since it means the second argument has to be a literal number (since it needs to be known at compile time):

然而,这仍然不是完美的,因为它意味着第二个参数必须是文字数(因为它需要在编译时知道):



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


In many cases that's not a problem, though.

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



To sum up: If you're willing to take responsibilty for reasonable code crashing your program, use productElement. If you want a little more safety (at the cost of some inconvenience), use productElement with Try. If you want compile-time safety (but some limitations), use Shapeless.

总而言之:如果您愿意为合理的代码崩溃承担责任,那么可以使用ProductElement。如果您想要更多的安全性(以一些不便为代价),可以结合使用ProductElement和Try。如果您想要编译时安全(但有一些限制),请使用Shapless。



Antoher typesafe way to do it without using shapeless is to provide a function to extract the element you need:

在不使用Shapless的情况下,类型安全的方法是提供一个函数来提取所需的元素:



def sumNth[T, E: Numeric](array: Array[T])(extract: T => E) =
array.map(extract).sum


Then you can define sum2nd like this:

然后您可以这样定义SumSecond:



def sum2nd(array: Array[(Int, Int, Int)]): Int = sumNth(array)(_._2)


Or like this:

或者像这样:



val sum2nd: Array[(Int, Int, Int)] => Int = sumNth(_)(_._2)


You could do something like this, though it's not really type safe:

您可以这样做,尽管它并不是真正的类型安全:



  def sumNth(aa: Array[Product], n: Int)= {
aa.map { a =>
a.productElement(n) match {
case i:Int => i
case _ => 0
}
}.sum
}

sumNth(Array((1,2,3), (2,3,4)), 2) // 7


Since Scala 3, elements of a tuple can be accessed by indexed with a function invocation-like syntax (e.g. t(1) to get the second element of a tuple t). The sumNth method can thus be implemented like so:

从Scala3开始,可以通过使用类似于函数调用的语法进行索引来访问元组的元素(例如,t(1)以获取元组的第二个元素t)。因此,SumNth方法可以按如下方式实现:


def sumNth(arr: Array[(Int, Int, Int)], n: Int) = arr.map(_(n).asInstanceOf[Int]).sum

Scastie Demo

SCastie演示


更多回答

This is a reasonable solution, if you ignore the fact that the OP is asking for a specific signature / usage. :)

如果忽略OP要求特定签名/用法这一事实,这是一个合理的解决方案。:)

Thanks for adding this answer, which I have upvoted. I just want to note that although Scala 3 has added this, the comments above about tuples being the wrong choice here still apply (except perhaps in some highly unusual contexts). Tuples are not collections.

谢谢你的回答,我已经投了赞成票。我只想指出,尽管Scala 3已经添加了这一点,但上面关于元组是错误选择的评论仍然适用(除非在一些非常不寻常的上下文中)。元组不是集合。

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com