Getting elements in a 2D vector (matrix)

I am looking for vector vectors for a specific int.

def searchVectors(i: Int, vectors: Vector[Vector[Int]]) = { val x = vectors.indexWhere(_.indexWhere(_ == i)) val y = vectors(x).indexOf(y) (x, y) } 

You can see that I get y twice. First, when calculating x, and then when calculating y. Not good. How to do this so that I only calculate y once?

thanks

+4
source share
4 answers

One approach you can take is to simply iterate over all the vectors:

 def searchVectors(x: Int, vec: Vector[Vector[Int]]) = for { i <- 0 until vec.size j <- 0 until vec(i).size if vec(i)(j) == x } yield (i, j) 

Vector also has a zipWithIndex method that adds an index to each element in the collection and creates a tuple from them. So you can use it to archive the same thing:

 def searchVectors(x: Int, vec: Vector[Vector[Int]]) = for { (subVec, i) <- vec.zipWithIndex (elem, j) <- subVec.zipWithIndex if elem == x } yield (i, j) 

The advantage of this approach is that instead of an outer (index-based) loop, you use an inner loop with map / flatMap . If you combine it with views, you can implement a lazy search:

 def searchVectors(x: Int, vec: Vector[Vector[Int]]) = for { (subVec, i) <- vec.view.zipWithIndex (elem, j) <- subVec.view.zipWithIndex if elem == x } yield (i, j) 

No, you will still receive a collection of results, but this is a lazy collection. Therefore, if you take it like this:

 searchVectors(3, vector).headOption 

It will perform a search (only at this point), and then when it is found, it will be returned as Option . No further searches will be performed.

+8
source

Here is a more functional approach:

 def searchVectors(i: Int, vectors: Vector[Vector[Int]]) = { val outer = vectors.toStream map (_.indexOf(i)) outer.zipWithIndex.filter(_._1 != -1).headOption map (_.swap) } 

EDIT: I think I like it even better:

 def searchVectors(i: Int, vectors: Vector[Vector[Int]]) = { vectors.toStream.map(_.indexOf(i)).zipWithIndex.collectFirst { case (y, x) if y != -1 => (x, y) } } 

Converting to Stream is optional, but probably more efficient, since it avoids searching for the entire vector if the desired element has already been found.

+3
source

It bothered me too. You may have already thought about this, but if you want to violate the principle of functional programming of an immutable state, etc., here is one possible approach:

 val v = Vector(Vector(1,2,3), Vector(4, 5, 6)) var c: Int = -1 val r = v.indexWhere(r => {c = r.indexOf(6); c != -1}) (r, c) 
+2
source

Here is an easy to understand solution.

 def searchVectors(i: Int, vectors: Vector[Vector[Int]]): (Int, Int) = { val row = vectors.indexWhere(_.contains(i)) // Try to get index of vector containing element if (row > -1) (row, vectors(row).indexOf(i)) // (row, col) else (-1, -1) } 
0
source

Source: https://habr.com/ru/post/1480329/


All Articles