scala - 在 Scala 中初始化一个二维(多维)数组

标签 scala multidimensional-array initialization

可以很容易地在 Java 中初始化一个 2D 数组(或者实际上是任何多维数组),方法如下:

int[][] x = new int[][] {
        { 3, 5, 7, },
        { 0, 4, 9, },
        { 1, 8, 6, },
};

它易于阅读,类似于二维矩阵等。

但是我如何在 Scala 中做到这一点?

我能想到的最好的外观,嗯,更不简洁:
val x = Array(
    Array(3, 5, 7),
    Array(0, 4, 9),
    Array(1, 8, 6)
)

我在这里看到的问题:
  • 它一遍又一遍地重复“数组”(就像除了 Array 之外还有其他任何东西)
  • 它需要省略尾随 ,在每次数组调用中
  • 如果我搞砸并插入除 Array() 之外的东西在数组中间,编译器没问题,但类型为 x会默默变成Array[Any]而不是 Array[Array[Int]] :
    val x = Array(
        Array(3, 5, 7),
        Array(0, 4), 9, // <= OK with compiler, silently ruins x
        Array(1, 8, 6)
    )
    

    有一个防范措施,直接指定类型,但它看起来比在 Java 中更加矫枉过正:
    val x: Array[Array[Int]] = Array(
        Array(3, 5, 7),
        Array(0, 4), 9, // <= this one would trigger a compiler error
        Array(1, 8, 6)
    )
    

    最后一个例子需要 Array甚至比我要说的还要多 3 倍 int[][]在 java 。

  • 有什么明确的方法可以解决这个问题吗?

    最佳答案

    我建议使用 Scala 2.10 和宏:

    object MatrixMacro {
    
      import language.experimental.macros
    
      import scala.reflect.macros.Context
      import scala.util.Try
    
      implicit class MatrixContext(sc: StringContext) {
        def matrix(): Array[Array[Int]] = macro matrixImpl
      }
    
      def matrixImpl(c: Context)(): c.Expr[Array[Array[Int]]] = {
        import c.universe.{ Try => _, _ }
    
        val matrix = Try {
          c.prefix.tree match {
            case Apply(_, List(Apply(_, List(Literal(Constant(raw: String)))))) =>
    
              def toArrayAST(c: List[TermTree]) =
                Apply(Select(Select(Ident("scala"), newTermName("Array")), newTermName("apply")), c)
    
              val matrix = raw split "\n" map (_.trim) filter (_.nonEmpty) map {
                _ split "," map (_.trim.toInt)
              }
              if (matrix.map(_.length).distinct.size != 1)
                c.abort(c.enclosingPosition, "rows of matrix do not have the same length")
    
              val matrixAST = matrix map (_ map (i => Literal(Constant(i)))) map (i => toArrayAST(i.toList))
    
              toArrayAST(matrixAST.toList)
          }
        }
    
        c.Expr(matrix getOrElse c.abort(c.enclosingPosition, "not a matrix of Int"))
      }
    
    }
    

    用法与:
    scala> import MatrixMacro._
    import MatrixMacro._
    
    scala> matrix"1"
    res86: Array[Array[Int]] = Array(Array(1))
    
    scala> matrix"1,2,3"
    res87: Array[Array[Int]] = Array(Array(1, 2, 3))
    
    scala> matrix"""
         |   1, 2, 3
         |   4, 5, 6
         |   7, 8, 9
         | """
    res88: Array[Array[Int]] = Array(Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9))
    
    scala> matrix"""
         |   1, 2
         |   1
         | """
    <console>:57: error: rows of matrix do not have the same length
    matrix"""
    ^
    
    scala> matrix"a"
    <console>:57: error: not a matrix of Int
                  matrix"a"
                  ^
    

    我不认为你会缩短它。 ;)

    关于scala - 在 Scala 中初始化一个二维(多维)数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13862568/

    相关文章:

    scala - 在gradle中使用sbt Avrohugger插件

    java - Scala - InvalidClassException : no valid constructor

    scala - 如何在 Galing 中引用 CSV Feeder 中的变量?

    python - 为什么 `a += x` 和 `a = a + x` 对于嵌套列表的实现方式不同?

    c - 初始化结构数组

    scala - 我可以在 where 或过滤器中有条件吗?

    php - 在多维数组php的内部数组上递归合并

    c++ - 二维数组的初始化如何工作?

    c - C 中以前的声明是否改变了指针的初始化方式?

    c++ - 模板的 typedef 是否保留静态初始化顺序?