我正在编写一个简单的scala程序,它将计算定义大小的引号列表的移动平均值,例如100。 报价将以每秒约5-6个报价的速度发布。
1)将引号保存在不可变的scala列表中是否很好?我猜每次引用时都会创建一个新的列表?是否需要花费太多不必要的记忆?
OR
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))
}*/
}
答案 0 :(得分:4)
这取决于您是否以相反的顺序保留项目。 List
会在开头的常量时间附加元素(::
将不创建一个全新的列表),而ListBuffer#+=
将在追加时创建一个节点它在列表的末尾。
使用List
和ListBuffer
之间应该存在很少或没有性能差异,也没有内存占用差异 - 内部这些是相同的数据结构。唯一的问题是你需要reverse
最后的列表 - 如果你愿意,这将需要创建第二个列表,所以它可能会更慢。
在您的情况下,使用列表缓冲区的决定是正确的 - 您需要删除第一个元素,并附加到集合的另一侧,这是普通功能列表不允许您有效执行的操作。< / p>
但是,在您的代码中,您在tail
上致电ListBuffer
。这实际上会复制列表缓冲区的内容,而不是给你一个便宜的尾部(O(WINDOW_SIZE)
操作)。你应该调用quotes.remove(0, 1)
删除第一个条目 - 这只会改变当前缓冲区,O(1)
操作。
对于非常快速的报价到货,您可以考虑使用自定义数据结构 - 对于列表缓冲区,您将支付装箱费用。
但是,如果每秒有5-6
个引号并且WINDOW_SIZE
在100
附近,则您不必担心 - 甚至在列表中调用tail
缓冲区应该是可以接受的。
答案 1 :(得分:0)
Scala中的不可变结构使用称为结构共享的技术。 对于列表,它也在Scaladocs中提到:
功能列表的特点是持久性和结构共享,因此在某些情况下可以提供相当大的性能和空间消耗优势。
所以:
至于代码:
如果你在下面的代码片段中处理文件,你不需要关心文件,同时也会同时处理文件
def processLines(path:String):Unit = for { line&lt; - Source.fromFile(“GBP_USD_Week1.csv”)。getLines.tail.par 记录&lt; - line.split(“,”) } processRecord(记录)