我正在寻找的是一种简洁的方式,最终得到一个不可变的二维数组 X 和一维数组 Y ,而不先扫描文件找出数据的维度。
由标题行后跟列式双精度值组成的数据采用以下格式
X0, X1, X2, ...., Y
0.1, 1.2, -0.2, ..., 1.1
0.2, 0.5, 0.4, ..., -0.3
-0.5, 0.3, 0.3, ..., 0.1
我有以下代码(到目前为止)从文件中获取行并标记每个逗号分隔行以获取样本。它目前不会填写 X 和 Y 数组,也不会分配 num 和 dimx
val X = new Array[Array[Double]](num,dimx)
val Y = new Array[Double](num)
def readDataFromFile(filename: String) {
var firstTime = true
val lines = fromFile(filename).getLines
lines.foreach(line => {
val tokens = line split(",")
if(firstTime) {
tokens.foreach(token => // get header titles and set dimx)
firstTime = false
} else {
println("data")
tokens.foreach(token => //blah, blah, blah...)
}
})
}
显然这是一个问题,因为虽然我可以即时检测并使用 dimx ,但我不知道 num 先验。此外,重复的tokens.foreach不是很优雅。我可以先扫描文件并确定尺寸,但这似乎是一种令人讨厌的方式。有没有更好的办法?提前致谢
答案 0 :(得分:3)
没有任何内置功能可以告诉您数据的大小。为什么不让方法返回你的数组而不是你在外面声明它们?这样你就可以更好地处理错误情况。
case class Hxy(headers: Array[String], x: Array[Array[Double]], y: Array[Double]) {}
def readDataFromFile(name: String): Option[Hxy] = {
val lines = io.Source.fromFile(name).getLines
if (!lines.hasNext) None
else {
val header = lines.next.split(",").map(_.trim)
try {
val xy = lines.map(_.split(",").map(_.trim.toDouble)).toArray
if (xy.exists(_.length != header.length)) None
else Some( Hxy(header, xy.map(_.init), xy.map(_.last)) )
}
catch { case nfe: NumberFormatException => None }
}
}
在这里,只有我们拥有格式良好的数据,我们才能获得相关数组(有帮助地打包到案例类中);否则,我们会回来None
,所以我们知道出了问题。
(如果您想知道它为什么不起作用,请将Option[Hxy]
替换为Either[String,Hxy]
,并在成功时返回Right(...)
而不是Some(...)
,{{1失败时代替Left(message)
。)
编辑:如果您希望值(不仅仅是数组大小)是不可变的,那么您需要将所有内容映射到某处的None
。当您将数据放入Vector
时,我可能会在最后一步执行此操作。
答案 1 :(得分:0)
Array
,与Java
一样可变。所以你不能拥有不可变数组。你需要在Array
和immutablity之间做出选择。一种方法是,如何在没有foreach
es和var
的情况下实现目标与以下内容类似:
// simulate the lines for this example
val lines = List("X,Y,Z,","1,2,3","2,5.0,3.4")
val res = lines.map(_.split(",")).toArray
答案 2 :(得分:0)
使用Array.newBuilder
。我假设标题已被提取。
val b = Array.newBuilder[Array[Double]]
lines.foreach { b += _.split(",").map(_.toDouble) }
val data = b.result
如果您想成为不可变的,请采用IndexedSeq
(例如Vector
)而不是Array
的一些不可变实现;建设者致力于所有馆藏。