Retrieving largest indices of the bounded element in a multidimensional array in Scala

跟風遠走 提交于 2019-12-13 13:16:54

问题


I have an multidimensional Array:

val M = Array.ofDim[Int](V, N)

Goal is to find largest V dimension index for which there exists a bounded element 0 < w0 <= W and return both indices and element value.

Currently I have this code snippet which works, but wondering if there is a nicer, more efficient way to do this.

M.zipWithIndex.reverse.collectFirst({
  case (arr, ind) if arr.exists(a => a <= W && a > 0) => {
    arr.zipWithIndex.find(a => a._1 <= W && a._1 > 0) match {
      case Some((weight, ind2)) => (ind, ind2, weight)
    }
  }
})

回答1:


You're really better off with an imperative or recursive solution here. I'll write a recursive one:

def finder(arr: Array[Array[Int]], w: Int, i: Int = 0, j: Int = 0): Option[(Int,Int,Int)] = {
  val ri = arr.length-i-1
  if (i >= arr.length) None
  else if (arr(ri)(j) > 0 && arr(ri)(j) < w) Some(ri,j,arr(ri)(j))
  else if (j+1 < arr(i).length) finder(arr,w,i,j+1)
  else finder(arr,w,i+1)
}

Then finder(M,W) should do what you want. Note that this is also efficient--no boxing aside from the return value.


Edit--if you care about performance, here are the runtimes of the existing solutions on a 100x100 array which has no solutions or one solution at 77% of the way to the end (i.e. runtime should be about 1/4):

Original without answer:     65 μs / iteration
Original with answer at 1/4: 18 μs / iteration

Result table compared to original method, relative time taken (lower is faster, compiled with -optimise but that hardly makes a difference):

                  No Answer    1/4 Answer
Original            1.00          1.00
Rex                 0.55          0.72
4e6                 1.95          7.00
missingfaktor       2.41          1.91
Luigi               4.93          3.92

So your original method was actually faster than all of the suggestions, save for the recursive one.




回答2:


Meh, pretty similar to the others, but it stops when it finds its target

def find(M: Array[Array[Int]], W: Int): Option[(Int, Int, Int)] = {
  for {
    x <- M.indices.reverse
    y <- M(x).indices
    a = M(x)(y)
    if 0 < a && a <= W
  } return Some(x, y, a)
  None
}



回答3:


As @Rex said, imperative approach in this case looks simpler

scala> val m = Array.tabulate(v,n)(_ + _)
m: Array[Array[Int]] = Array(Array(0, 1, 2, 3), Array(1, 2, 3, 4), Array(2, 3, 4, 5))

scala> for { 
     | i <- v-1 to 0 by -1
     | j <- n-1 to 0 by -1
     | if m(i)(j) > 0 && m(i)(j) < 2
     | } yield (i, j, m(i)(j))
res23: scala.collection.immutable.IndexedSeq[(Int, Int, Int)] = Vector((1,0,1), (0,1,1))

scala> res23.headOption
res24: Option[(Int, Int, Int)] = Some((1,0,1))



回答4:


I would write an iterator.

scala> def itr[A](as: Array[Array[A]]) = new Iterator[(Int, Int, A)] {
     |   private var r = 0 
     |   private var c = -1
     |   def next = {
     |     if(c == as(r).length - 1) {
     |       c = 0
     |       r += 1
     |     } else {
     |       c += 1
     |     }
     |     (r, c, as(r)(c))
     |   }
     |   def hasNext = {
     |     !((r == as.length - 1) && (c == as(r).length - 1))
     |   }
     | }
itr: [A](as: Array[Array[A]])java.lang.Object with Iterator[(Int, Int, A)]

scala> val xs = Array.tabulate(5, 6)(_ + _)
xs: Array[Array[Int]] = Array(Array(0, 1, 2, 3, 4, 5), Array(1, 2, 3, 4, 5, 6), Array(2, 3, 4, 5, 6, 7), Array(3, 4, 5, 6, 7, 8), Array(4, 5, 6, 7, 8, 9))

scala> itr(xs).find { case (_, _, x) => 5 < x && x <= 7 }
res19: Option[(Int, Int, Int)] = Some((1,5,6))


来源:https://stackoverflow.com/questions/8421840/retrieving-largest-indices-of-the-bounded-element-in-a-multidimensional-array-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!