在Scala中初始化2D(多维)数组

Gre*_*Cat 25 scala initialization multidimensional-array

通过放置类似的内容,可以很容易地在Java中初始化2D数组(或者实际上是任何多维数组):

int[][] x = new int[][] {
        { 3, 5, 7, },
        { 0, 4, 9, },
        { 1, 8, 6, },
};
Run Code Online (Sandbox Code Playgroud)

它易于阅读,类似于2D矩阵等.

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

最好的我可以想出看起来,更简洁:

val x = Array(
    Array(3, 5, 7),
    Array(0, 4, 9),
    Array(1, 8, 6)
)
Run Code Online (Sandbox Code Playgroud)

我在这里看到的问题:

  • 它一遍又一遍地重复"数组"(比如除了之外还有其他的东西Array)
  • 它需要,在每个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)
    )
    
    Run Code Online (Sandbox Code Playgroud)

    有一个防范它,直接指定类型,但它看起来比在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)
    )
    
    Run Code Online (Sandbox Code Playgroud)

    最后一个例子Array甚至需要比我int[][]在Java中说的多3倍.

这有什么明确的方法吗?

Lui*_*hys 16

就个人而言,为了清楚起见,我会把它吸干并输入(或剪切和粘贴)"Array"几次.当然,包括安全类型注释.但是,如果你真的没电子墨水,快速简单的黑客就是提供别名Array,例如:

val > = Array

val x: Array[Array[Int]] = >(
  >(3, 5, 7),
  >(0, 4, 9),
  >(1, 8, 6)
)
Run Code Online (Sandbox Code Playgroud)

Array如果要缩短注释,还可以提供类型别名:

type >[T] = Array[T]

val x: >[>[Int]] = ...
Run Code Online (Sandbox Code Playgroud)

  • 我打算在"我吮吸它"的基础上进行投票.因为我不想满足于香草语法.但是你的类型别名不仅仅是弥补了它,所以你收到了一个upvote;) (3认同)

kir*_*uku 13

我建议使用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"))
  }

}
Run Code Online (Sandbox Code Playgroud)

用法:

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"
              ^
Run Code Online (Sandbox Code Playgroud)

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


Rég*_*les 5

如果仅使用Listof List(它本身不能保证每个子列表的大小相同)对您来说不是问题,并且您只关心简单的语法并避免创建时的错误,那么 scala 有多种方法可以创建很好的语法结构。

其中一种可能性是一个简单的助手:

object Matrix {
  def apply[X]( elements: Tuple3[X, X, X]* ): List[List[X]] = {
    elements.toList.map(_.productIterator.toList.asInstanceOf[List[X]] )
  }
  // Here you might add other overloads for Tuple4, Tuple5 etc if you need "matrixes" of those sizes
}

val x = Matrix(
  (3, 5, 7),
  (0, 4, 9),
  (1, 8, 6)
)
Run Code Online (Sandbox Code Playgroud)

关于您的疑虑:

它一遍又一遍地重复“List”(就像除了 List 之外还可能有其他东西一样)

这里的情况并非如此。

它需要在每个 List 调用中省略尾随 ,

不幸的是,这仍然是正确的,考虑到 scala 的语法规则,你无能为力。

如果我搞砸了并在数组中间插入除 List() 之外的其他内容,编译器会正常工作,但 x 的类型会默默地变成 List[Any] 而不是 List[List[Int]]:

val x = List(
  List(3, 5, 7),
  List(0, 4), 9, // <= OK with compiler, silently ruins x
  List(1, 8, 6)
)
Run Code Online (Sandbox Code Playgroud)

等效代码现在无法编译:

scala> val x = Matrix(
     |   (3, 5, 7),
     |   (0, 4), 9,
     |   (1, 8, 6)
     | )
<console>:10: error: type mismatch;
 found   : (Int, Int)
 required: (?, ?, ?)
         (0, 4), 9,
Run Code Online (Sandbox Code Playgroud)

最后,如果您想显式指定元素的类型(假设您想防止无意中混合Ints 和Doubles 的可能性),您只需指定Matrix[Int]而不是丑陋的List[List[Int]]

val x = Matrix[Int](
  (3, 5, 7),
  (0, 4, 9),
  (1, 8, 6)
)
Run Code Online (Sandbox Code Playgroud)

编辑:我看到你在问题中List替换了。Array要使用数组,您只需在上面的代码中替换ListwithArraytoListwith即可。toArray

  • 可以使用“shapeless”来推广 TupleN 的解决方案。 (2认同)