【问题标题】:How to concisely build up a Scala List from dependent elements?如何从依赖元素简明扼要地构建一个 Scala 列表?
【发布时间】:2012-10-30 11:30:12
【问题描述】:

我想构建一个Foo 对象的List,每个对象都是通过从最后一个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)}

【问题讨论】:

    标签: list parsing function scala recursion


    【解决方案1】:

    我的又快又脏?解决方案在这里:

    //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))  
    

    【讨论】:

      【解决方案2】:

      如果不能事先拆分数组,则需要使用显式递归,例如:

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

      【讨论】:

        猜你喜欢
        • 2015-01-19
        • 1970-01-01
        • 2011-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-16
        相关资源
        最近更新 更多