从给定点列出2D数组的对角元素的最快方法

时间:2015-04-10 17:42:00

标签: arrays scala functional-programming

在2D数组中,对于给定点,获取Scala中对角线元素的最快方法是什么?我知道我可以简单地使用for循环来遍历给定点的元素,但感觉非常像java。我提出的一种方法是使用递归函数,该函数接受函数作为计算下一个单元格的参数。但是我觉得这样的方法效率很低。在Scala中穿越对角线最惯用的方式是什么?

3 个答案:

答案 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
}