Scala:以理解方式迭代数组的索引,但确保结果类型与数组类型相同

Scala: Iterate an Array's indices in for-comprehension but ensure result type is same Array type

我知道在 for-comprehension 中找到的第一个序列的序列类型定义了推导式的输出类型。但是我需要在不牺牲理解语法的使用的情况下解决这个问题。

假设我有一些名为 vArray[Double] 和一些名为 condition 的复杂谓词函数,它基于 索引 v,如果 condition(i) 的计算结果为真,那么我想保留 v 的元素。它类似于使用 filter,除了过滤发生在索引上,而不是 v.

的值上

我想通过对索引的理解来有效地表达这一点,但我希望结果的类型是 Array[Double] 而不是 Array.indices 的类型。

这是一个最小的示例,其中 condition 只是一个计算索引是否为偶数的玩具示例。实际用例涉及检查二维数组中的索引,其中某些图像梯度条件为真,但想法与这个简单示例相同。

scala> val v = Array[Double](8.0, 9.0, 10.0, 11.0, 12.0)
v: Array[Double] = Array(8.0, 9.0, 10.0, 11.0, 12.0)

scala> def condition(x: Int): Boolean = {x % 2 == 0} // but could be complex
condition: (x: Int)Boolean

scala> for (i <- v.indices if condition(i)) yield v(i)
res136: scala.collection.immutable.IndexedSeq[Double] = Vector(8.0, 10.0, 12.0)

for-comprehension 的输出是 scala.collection.immutable.IndexedSeq[Double] 类型,但我正在寻找如何确保它只是 Array[Double],而不需要显式类型转换。

基本上,如果我从 foo.indices 迭代,并且生成的项目来自 foo(i),我正在寻找一种方法来自动使用 foo 的类型作为结果,所以容器类型与迭代的任何类型的索引相匹配。

Scala 中正确的习语是什么,用于确保需要专门针对索引范围的 for-comprehension 的结果类型,但结果的容器类型应与索引对象的容器类型相匹配-正在使用而不是索引序列本身的类型(这对理解来说无关紧要)?

  1. 使用zipWithIndex。在Array的情况下,它会产生Array[(Double, Int)],而不是一些奇怪的IndexedSeq

    for ((a, i) <- v.zipWithIndex if condition(i)) yield a
    
  2. 使用breakOut

    import collection.breakOut
    val res: Array[Double] = (
      for (i <- v.indices if condition(i)) yield v(i)
    )(breakOut)
    
  3. 最后用toArray转换一下结果,以后有需要的时候再优化一下。

  4. 另请注意,通常可以为所有具有 Traverse 类型类的集合定义 zipWithIndex。在假设有 Traverse[F] 可用的情况下,将 F[A] 转换为 F[(A, Int)] 是一种通用方法。