如何从依赖元素简洁地构建Scala列表?

时间:2012-11-10 06:57:04

标签: list parsing function scala recursion

我想构建一个ListFoo个对象,每个对象都是通过读取从最后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}}

2 个答案:

答案 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)。