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

时间:2018-06-29 20:02:09

标签: scala sequence for-comprehension resulttype

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

假设我有一些Array[Double],称为v,还有一些复杂的谓词函数,称为condition,它基于v indices ,并且如果condition(i)的计算结果为true,那么我想保留v的元素。类似于使用filter,只是过滤发生在索引上,而不是v的值上。

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

这是一个最小的示例,其中condition只是计算索引是否为偶数的玩具示例。实际用例涉及检查2D数组中的某些图像渐变条件是否成立的索引,但是思想与这个简单示例相同。

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)

要理解的输出的类型为scala.collection.immutable.IndexedSeq[Double],但我正在寻求如何确保它只是Array[Double],而无需显式的类型转换。

基本上,如果我从foo.indices进行迭代,而产生的项来自foo(i),则我正在寻找一种自动为结果使用foo类型的方法,以便容器类型匹配要迭代的任何类型的索引。

Scala中正确的习惯用法是什么,以确保需要理解的理解类型的结果类型需要特别在索引范围内,但是结果的容器类型应该与事物的容器类型匹配(索引对象是谁)而不是索引序列本身的类型(对于理解来说是无关紧要的)?

1 个答案:

答案 0 :(得分:5)

  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。在假定有F[A]可用的情况下,将F[(A, Int)]转换为Traverse[F]的一般方法。