在2D数组中,对于给定点,获取Scala中对角线元素的最快方法是什么?我知道我可以简单地使用for循环来遍历给定点的元素,但感觉非常像java。我提出的一种方法是使用递归函数,该函数接受函数作为计算下一个单元格的参数。但是我觉得这样的方法效率很低。在Scala中穿越对角线最惯用的方式是什么?
答案 0 :(得分:4)
Scala中的快速功能代码通常涉及尾递归函数,快速数组访问通常涉及索引。所以你的选择是有限的。
在这种情况下,
def diag(xss: Array[Array[Double]]): Array[Double] = {
val ans = new Array[Double](xss.length)
@annotation.tailrec def inner(i: Int) {
if (i < xss.length) {
ans(i) = xss(i)(i)
inner(i+1)
}
}
inner(0)
ans
}
就个人而言,我发现这不如相应的while循环
def diag(xss: Array[Array[Double]]): Array[Double] = {
val ans = new Array[Double](xss.length)
var i = 0
while (i < xss.length) {
ans(i) = xss(i)(i)
i += 1
}
ans
}
但您的偏好可能会有所不同。
有一些优化框架将采用高阶索引遍历(例如for (i <- xss.indices) ans(i) = xss(i)(i)
)并将其更改为while循环。 (ScalaBlitz就是其中之一。)
答案 1 :(得分:1)
您还可以使用Tail recursion
和不可变数据结构(如List
)作为函数式编程和不变性。它提供了两个操作头部和尾部,它们需要恒定的时间和两个操作的时间复杂度为O(1)。
@annotation.tailrec
def f(arr: List[List[Int]], res: List[Int] = Nil): List[Int] = {
if (arr.isEmpty) res
else
f(arr.tail.map(_.tail), res :+ arr.head.head)
}
val x = List(List(1, 2, 3, 4), List(5, 6, 7, 8), List(9, 10, 11, 12), List(13, 14, 15, 16))
scala> f(x)
res0: List[Int] = List(1, 6, 11, 16)
答案 2 :(得分:0)
只是为了好玩,一些(可以说是)更通俗的Scala,注意到对角线元素是从线的旋转发出的,你可以使用如下代码。它虽然效率低于for循环。
def diag(m: Array[Array[Int]]) = {
val (m1, m2) = m.zipWithIndex.
map{case (l, i) => val (l1, l2) = splitAt(l.size-i); l1 ++ l2}.
transpose.zipWithIndex.
map{case (l, i) => l.splitAt(i+1)}.
unzip
m1 ++ m2.init
}