我想构建一个List
个Foo
个对象,每个对象都是通过读取从最后Foo
完成的字节数组开始构造的。鉴于构建时唯一需要的状态是到目前为止的内容和读取的字节数,我想通过重复应用将较小的List
转换为较大的List
的函数来实现这一点。在每一步中,当前List
作为参数传递(可能是到目前为止读取的字节数,以避免重新解析)并返回附加的元素。因为这似乎是一种非常简单的方法来构建bytesToList
我感兴趣但是找不到我可以使用的库函数是不成功的。以下是我要做的事情的必要示例,我想使def bytesToList(bytes: Array[Byte]): List[Foo] =
{
var numBytesRead = 0
var listToBuild = List[Foo]()
while (numBytesRead < bytes.length)
{
listToBuild ::= new Foo(bytes, numBytesRead)
numBytesRead += listToBuild.last.bytesRead
}
listToBuild
}
class Foo(bytesToRead: Array[Byte], startReadingAt: Int)
{val bytesRead = Random.nextInt(bytesToRead.length)}
无状态且更简洁的功能:
{{1}}
答案 0 :(得分:3)
我又快又脏?解决方案在这里:
//some random source for bytes
def bytes(count: Int): Stream[Byte] = {
var byteArray: Array[Byte] = new Array(count)
Random.nextBytes(byteArray)
(for {i <- (0 to count-1) } yield byteArray(i)).toStream
}
class Foo(b1: Byte, b2: Byte, pb: (Byte, Byte)) {
def this(bytes4foo: Array[Byte]) = this( bytes4foo(0), bytes4foo(1), (bytes4foo(2), bytes4foo(3)) )
def sizeOf: Int = 4
override def toString = "Foo("+b1+", "+b2+", "+pb+")"
}
def bytesToList(source: Stream[Byte]): List[Foo] = {
val afoo = new Foo(0,0,(0,0)) // ~ static Foo.sizeOf
def moreFoo(next: Stream[Byte]): List[Foo] = {
if (next == Stream.Empty) Nil
else new Foo(source.take(afoo.sizeOf).toArray) :: bytesToList(source.drop(afoo.sizeOf))
}
moreFoo(source)
}
用以下方法测试:
bytesToList(bytes(20)) mkString "\n"
//> res1: String = Foo(-73, 63, (-14,107))
//| Foo(-61, 105, (-124,-44))
//| Foo(117, 79, (-79,-17))
//| Foo(-84, -116, (13,-3))
//| Foo(93, -110, (30,36))
答案 1 :(得分:3)
如果无法预先拆分数组,则需要使用显式递归,例如:
def bytesToList(bytes: Array[Byte], n: Int = 0): List[Foo] =
if (n >= bytes.length) Nil
else {
val foo = new Foo(bytes, n)
foo :: bytesToList(bytes, n + foo.bytesRead)
}
我不知道你期望拥有的Foos怎么样,但如果它超过一千个左右,最好让这个尾部递归以避免炸毁堆栈(提示:添加一个额外的参数对于输出,默认值为Nil
)。