我正在为特定的 int 搜索向量向量。
def searchVectors(i: Int, vectors: Vector[Vector[Int]]) = {
val x = vectors.indexWhere(_.indexWhere(_ == i))
val y = vectors(x).indexOf(y)
(x, y)
}
你可以看到我得到了两次 y。首先在计算 x 时,然后在计算 y 时再次。不好。我该怎么做才能只计算 y 一次?
谢谢
我正在为特定的 int 搜索向量向量。
def searchVectors(i: Int, vectors: Vector[Vector[Int]]) = {
val x = vectors.indexWhere(_.indexWhere(_ == i))
val y = vectors(x).indexOf(y)
(x, y)
}
你可以看到我得到了两次 y。首先在计算 x 时,然后在计算 y 时再次。不好。我该怎么做才能只计算 y 一次?
谢谢
您可以采取的一种方法是迭代所有向量:
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 也有zipWithIndex
方法,它为集合的每个元素添加索引并创建它们的元组。因此,您可以使用它来归档相同的内容:
def searchVectors(x: Int, vec: Vector[Vector[Int]]) =
for {
(subVec, i) <- vec.zipWithIndex
(elem, j) <- subVec.zipWithIndex
if elem == x
} yield (i, j)
这种方法的优点是,您使用的是内部循环而不是外部(基于索引)循环map
/ flatMap
。如果将其与视图结合使用,则可以实现惰性搜索:
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)
不是你仍然会收到结果集合,但它是惰性集合。因此,如果您要这样处理它:
searchVectors(3, vector).headOption
它实际上会执行搜索(仅在此时),然后,当它被找到时,它会以Option
. 不会进行进一步的搜索。
这是一种更实用的方法:
def searchVectors(i: Int, vectors: Vector[Vector[Int]]) = {
val outer = vectors.toStream map (_.indexOf(i))
outer.zipWithIndex.filter(_._1 != -1).headOption map (_.swap)
}
编辑:我想我更喜欢这个:
def searchVectors(i: Int, vectors: Vector[Vector[Int]]) = {
vectors.toStream.map(_.indexOf(i)).zipWithIndex.collectFirst {
case (y, x) if y != -1 => (x, y)
}
}
转换为 aStream
是可选的,但可能更有效,因为如果已经找到所需的元素,它会避免搜索整个向量。
这也让我很困扰。您可能已经想到了这一点,但是如果您愿意违反不可变状态等函数式编程原则,这是一种可能的方法:
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)
这是一个易于理解的解决方案
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)
}