在Scala中初始化2D(多维)数组 [英] Initializing a 2D (multi-dimensional) array in Scala
问题描述
通过在Java中放置类似这样的内容,可以很容易地初始化2D数组(或者实际上是任何多维数组):
It's easy to initialize a 2D array (or, in fact, any multidimensional array) in Java by putting something like that:
int[][] x = new int[][] {
{ 3, 5, 7, },
{ 0, 4, 9, },
{ 1, 8, 6, },
};
它易于阅读,类似于2D矩阵等.
It's easy to read, it resembles a 2D matrix, etc, etc.
但是我该如何在Scala中做到这一点?
But how do I do that in Scala?
我想出的最好的外观,简明扼要得多:
The best I could come up with looks, well, much less concise:
val x = Array(
Array(3, 5, 7),
Array(0, 4, 9),
Array(1, 8, 6)
)
我在这里看到的问题:
- 它一遍又一遍地重复数组"(就像
Array
之外可能还有其他东西一样) - 在每次调用数组时都需要省略尾随
,
-
如果我拧紧并在数组中间插入除
Array()
之外的内容,则对于编译器来说还可以,但是x
的类型将默默地变为Array[Any]
而不是Array[Array[Int]]
: >
- It repeats "Array" over and over again (like there could be anything else besides
Array
) - It requires to omit trailing
,
in every Array invocation If I screw up and insert something besides
Array()
in the middle of array, it will go okay with compiler, but type ofx
would silently becomeArray[Any]
instead ofArray[Array[Int]]
:
val x = Array(
Array(3, 5, 7),
Array(0, 4), 9, // <= OK with compiler, silently ruins x
Array(1, 8, 6)
)
有一种防范措施,可以直接指定类型,但是它看上去比Java中的矫kill过正:
There is a guard against it, to specify the type directly, but it looks even more overkill than in 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
甚至是我在Java中要说int[][]
的三倍.
This last example needs Array
even 3 times more than I have to say int[][]
in Java.
有没有解决的办法?
推荐答案
我建议使用Scala 2.10和宏:
I suggest to use Scala 2.10 and macros:
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"
^
我不认为您会更短. ;)
I don't think you will get it shorter. ;)
这篇关于在Scala中初始化2D(多维)数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!