1

我正在编写一个简单的 scala 程序,它将计算定义大小的报价列表的移动平均值,比如 100。报价将以每秒大约 5-6 个报价的速度出现。

1)将引号保留在不可变的scala列表中是否很好,我猜每次引用出现时都会创建一个新列表?会不会占用太多不必要的内存?

或者

2)将引号保留在像 ListBuffer 这样的可变列表中是否很好,其中我将删除最旧的引号并在每次引用出现时推送新引号。

当前代码

package com.example.csv

import scala.io.Source
import scala.collection.mutable.ListBuffer

object CsvFileParser {
  val WINDOW_SIZE = 25;
  var quotes = ListBuffer(0.0);
  def main(args: Array[String]) = {
    val src = Source.fromFile("GBP_USD_Week1.csv");
    //drop header and split the comma separated tokens
    val iter = src.getLines().drop(1).map(_.split(","));
    // Sliding window reads ahead // remove it
    val index = 0;

    while(iter.hasNext) {
     processRecord(iter.next) 
    }
    src.close()
  }

  def processRecord(record: Array[String]) = {
    if(quotes.length < WINDOW_SIZE){
      quotes += record(4).toDouble; 
    }else {
      val movingAverage = quotes.sum / quotes.length
      quotes.map(_ + " ").foreach(print)
      println("\nMoving Average " + movingAverage)
      quotes = quotes.tail;
      quotes += record(4).toDouble;

    }
  }

  /*def simpleMovingAverage(values: ListBuffer[Double], period: Int): ListBuffer[Double] = {
      ListBuffer.fill(period - 1)(0.0) ++ (values.sliding(period).map(_.sum).map(_ / period))  
  }*/

}
4

2 回答 2

4

这取决于您是否以相反的顺序保留项目。Lists 将在开始时以恒定的时间附加元素(::不会创建一个全新的列表),而sListBuffer#+=将在将其附加到列表的末尾时创建一个节点。

List使用和ListBuffer-- 在内部这些是相同的数据结构之间,性能差异或内存占用差异应该很小或没有差异。唯一的问题是您是否需要reverse最后的列表 - 如果需要,这将需要创建第二个列表,因此它可能会更慢。

在您的情况下,使用列表缓冲区的决定是正确的——您需要删除第一个元素,并附加到集合的另一侧,这是普通功能列表不允许您有效执行的操作。

但是,在您的代码中,您调用tail. ListBuffer这实际上会复制列表缓冲区的内容,而不是给你一个便宜的尾巴(O(WINDOW_SIZE)操作)。您应该调用quotes.remove(0, 1)来删除第一个条目——这只会改变当前缓冲区,一个O(1)操作。

对于非常快的报价到达,您可以考虑使用自定义数据结构——对于列表缓冲区,您将支付装箱成本。5-6但是,如果每秒有引号并且WINDOW_SIZE是 around 100,您不必担心——即使调用tail列表缓冲区也应该是可以接受的。

于 2013-04-17T17:45:53.370 回答
0

Scala 中的不可变结构使用一种称为结构共享的技术。对于列表,Scaladocs 中也提到了它:

功能列表具有持久化和结构共享的特点,因此在某些场景下提供了可观的性能和空间消耗优势。

所以:

  • 不可列表将占用更多空间,但不会更多,并且会更好地与其他 Scla 构造融合
  • 可变版本容易出现并发问题,会更快一点,使用的空间也少一点。

至于代码:

  • 如果您使用可变结构,则可以摆脱 var,如果您想覆盖不可变结构,请保留它
  • 具有返回列表而不是操作可变结构或具有全局变量的方法将被认为是好的样式
  • 如果你像下面的代码片段那样处理文件,你不需要关闭文件,文件也会被同时处理

    def processLines(path: String) : Unit = for { line <- Source.fromFile("GBP_USD_Week1.csv").getLines.tail.par record <- line.split(",") } processRecord(record)

于 2013-04-17T17:52:52.713 回答