我希望以函数方式在Int的嵌套Vector
中找到值为4的第一个元素的索引(坐标)。
val a = Vector(Vector(1,2,3), Vector(4,5), Vector(3,8,4))
a.map(_.zipWithIndex).zipWithIndex.collect{
case (col, i) =>
col.collectFirst {
case (num, index) if num == 4 =>
(i, index)
}
}.collectFirst {
case Some(x) ⇒ x
}
它返回:
Some((0, 1))
前4次出现的坐标。
这个解决方案非常简单,但它会降低性能,因为当我们只对第一个匹配感兴趣时,会对顶部Vector的所有元素执行嵌套col.collect
。
一种可能的解决方案是在模式匹配中编写一个保护。但我不知道如何在缓慢的条件下写一个后卫,并返回已经在守卫中计算过的东西。
可以做得更好吗?
答案 0 :(得分:1)
可能递归吗?
如果你坚持使用Vector
s,这样的东西就可以了(对于非索引的seq,你需要一个不同的方法):
@tailrec
findit(
what: Int,
lists: IndexedSeq[IndexedSeq[Int]],
i: Int = 0,
j: Int = 0
): Option[(Int, Int)] =
if(i >= lists.length) None
else if(j >= lists(i).length) findit(what, lists, i+1, 0)
else if(lists(i)(j) == what) Some((i,j))
else findit(what, lists, i, j+1)
答案 1 :(得分:0)
在不更改算法的情况下,您可以轻松使用Scala流,以便在找到匹配后立即退出。与序列相反,流被懒惰地评估。
只需进行类似于此的更改
a.map(_.zipWithIndex.toStream).zipWithIndex.toStream.collect{ ...
在算法更改方面,如果您可以以某种方式对数据进行排序(甚至在开始搜索之前),那么您可以使用Binary search
而不是查看每个元素。
import scala.collection.Searching._
val dummy = 123
implicit val anOrdering = new Ordering[(Int, Int, Int)]{
override def compare(x: (Int, Int, Int), y: (Int, Int, Int)): Int = Integer.compare(x._1, y._1)
}
val seqOfIntsWithPosition = a.zipWithIndex.flatMap(vectorWithIndex => vectorWithIndex._1.zipWithIndex.map(intWithIndex => (intWithIndex._1, vectorWithIndex._2, intWithIndex._2)))
val sorted: IndexedSeq[(Int, Int, Int)] = seqOfIntsWithPosition.sortBy(_._1)
val element = sorted.search((4, dummy, dummy))
这段代码不是很漂亮或可读,我很快就想展示一下它是如何完成的。