我有一个代码需要很长时间才能计算 Array[Array[Array[Double]]],但我需要结果来计算具有不同参数但相同 Array[Array[Array[Double]]] 的其他内容,因此它将其放在我的文件中并导入会更方便。我可以制作一个长字符串,将每一行依次放置,但我想有一种更复杂的方法可以做到这一点。只需导入此文件就可以了,我可以将其用作 Array[Array[Array[Double]]]。所以我需要你的帮助。谢谢
我尝试过将其转换为长字符串并导出,但结果很混乱。
这取决于您将使用什么语言进行其他计算。 我想提出两种变体
如果您不打算使用 scala 以外的其他语言,存储数组的最快方法将是使用 Serialized 进行纯 JVM 序列化。
一个简单的解决方案是按照某种自定义格式编写一个纯文件。
这是一个示例,如果您的数据是对称的(例如所有内部
Arrays
具有相同的大小)。Array
的大小,然后每个元素写入一行。
def writeData(data: Data)(writeLine: String => Unit): Unit =
val tensors = data.length
val rows = if (tensors > 0) data.head.length else 0
val columns = if (rows > 0) data.head.head.length else 0
// Print header line.
writeLine(s"${tensors},${rows},${columns}")
// You may use while loops here if you prefer.
data.foreach { row =>
row.foreach { column =>
column.foreach { value =>
writeLine(value.toString)
}
}
}
end writeData
您可以使用更好的名称。
然后,阅读功能也非常简单:
def readData(lines: Iterator[String]): Data =
// We are assuming here the file has at least the header line.
val header = lines.next().split(',')
val tensors = header(0).toInt
val rows = header(1).toInt
val columns = header(2).toInt
// You may use while loops here if you prefer.
ArraySeq.fill(tensors, rows, columns) {
// We are assuming here the file only has double values.
lines.next().toDouble
}
end readData
如果您认为错误处理很重要,您可以添加错误处理。
您可以在Scastie
中看到代码运行
它使用
List
作为内存中的文件只是为了表明它可以工作,真正的代码将使用真正的 I/O API,无论您喜欢哪种; Java nio
、Java io
、Scala Source
(仅适用于阅读)、better-files、akka、fs2 等
另一件事要考虑的是直接使用
Bytes
而不是Strings
,这会节省大量的编码和解码时间和文件大小;但代价是它不可读。Ints
和 Doubles
具有固定大小,因此您可以将前三个 Ints
,然后将所有 Doubles
写入二进制文件。然后,在阅读时,您将得到 Iterator[String]
,而不是 Iterator[Byte]
,然后您将使用 ByteBuffer
进行转换:
def writeData(data: Data)(writeByte: Byte => Unit): Unit =
val tensors = data.length
val rows = if (tensors > 0) data.head.length else 0
val columns = if (rows > 0) data.head.head.length else 0
def writeInt(value: Int): Unit =
ByteBuffer.allocate(4).putInt(value).array.foreach(writeByte)
end writeInt
writeInt(tensors)
writeInt(rows)
writeInt(columns)
def writeDouble(value: Double): Unit =
ByteBuffer.allocate(8).putDouble(value).array.foreach(writeByte)
end writeDouble
data.foreach { row =>
row.foreach { column =>
column.foreach(writeDouble)
}
}
end writeData
def readData(lines: Iterator[Byte]): Data =
def readInt(): Int =
val bb = ByteBuffer.allocate(4)
bb.put(lines.next())
bb.put(lines.next())
bb.put(lines.next())
bb.put(lines.next())
bb.getInt(0)
end readInt
val tensors = readInt()
val rows = readInt()
val columns = readInt()
def readDouble(): Double =
val bb = ByteBuffer.allocate(8)
bb.put(lines.next())
bb.put(lines.next())
bb.put(lines.next())
bb.put(lines.next())
bb.put(lines.next())
bb.put(lines.next())
bb.put(lines.next())
bb.put(lines.next())
bb.getDouble(0)
end readDouble
ArraySeq.fill(tensors, rows, columns)(readDouble())
end readData
您可以在Scastie
中看到代码运行如果您的数据不对称,您将需要稍微调整代码。您需要有多个 “开始部分” 类型的行来说明接下来将有多少个元素,而不是单个标题。该版本甚至可以通用以写入和读取任意数量的嵌套
Arrays
。
最后,您可以考虑使用像 scodec 这样的库来处理二进制数据。