【问题标题】:map Range directly to Array将 Range 直接映射到 Array
【发布时间】:2017-09-06 13:50:00
【问题描述】:

以下代码创建一个临时向量:

0.to(15).map(f).toArray
^^^^^^^^
Sequence
^^^^^^^^^^^^^^^
    temp Vector
^^^^^^^^^^^^^^^^^^^^^^^
                  Array

以下代码创建一个临时数组:

0.to(15).toArray.map(f)
^^^^^^^^
Sequence
^^^^^^^^^^^^^^^
     temp Array
^^^^^^^^^^^^^^^^^^^^^^^
                  Array

有没有办法在序列上映射 f 并直接获取一个数组,而不产生临时?

【问题讨论】:

    标签: arrays scala vector mapping temporary


    【解决方案1】:

    你可以使用breakOut:

    val res: Array[Int] = 0.to(15).map(f)(scala.collection.breakOut)
    

    0.to(15).map[Int, Array[Int]](f)(scala.collection.breakOut)
    

    或使用view:

    0.to(15).view.map(f).to[Array]
    

    有关查看的更多详细信息,请参阅this document

    【讨论】:

    • 您能简单解释一下breakOut 的作用吗?
    • 另外,似乎0.to(15).map[Int, Array[Int]](f) 已经可以在没有额外的(scala.collection.breakOut) 参数列表的情况下工作。
    • 简而言之,breakOut 是一种根据所需的输入和输出类型找到正确的CanBuildFrom 实例的方法,否则编译器可能无法正确推断。使用正确的 CanBuildFrom 实例,您可以在映射原始集合的同时创建新类型的集合。更多详情stackoverflow.com/questions/1715681/scala-2-8-breakout
    • 0.to(15).map[Int, Array[Int]](_ + 1) 在 Scala 2.12.3 中对我不起作用,因为编译器抱怨无法找到 CanBuildFrom
    • 在我的例子中,f 是一个具体的函数,所以编译器已经知道类型。它是否适用于 (_ + 1: Int => Int) 或类似的东西?
    【解决方案2】:
    (0 to 15).iterator.map(f).toArray
    

    【讨论】:

      【解决方案3】:

      如果您知道如何构建初始 Range,您也可以使用 Array.range(start, end)Array companion object 直接创建一个 Range 作为 Array 而无需转换:

      Array.range(0, 15) // Array[Int] = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
      

      可以像这样从Array 映射到Array

      Array.range(0, 15).map(f) // Array[Int] = Array(0, 2, 4, 6, 8, 10, 12, 14, ...)
      

      注意Array.range(i, j) 等效于 i until j (i to j+1) 而不是 i to j


      使用Array.tabulate 时更短,一次通过,但可读性较差:

      Array.tabulate(15)(f) // Array[Int] = Array(0, 2, 4, 6, 8, 10, 12, 14, ...)
      

      【讨论】:

        猜你喜欢
        • 2018-07-21
        • 2017-09-23
        • 1970-01-01
        • 2022-01-17
        • 2018-02-09
        • 2015-02-03
        • 2021-05-31
        • 2018-06-24
        相关资源
        最近更新 更多