Scala - Mutable ListBuffer或Immutable列表可供选择?

时间:2013-04-17 16:59:08

标签: list scala immutability

我正在编写一个简单的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))  
  }*/

}

2 个答案:

答案 0 :(得分:4)

这取决于您是否以相反的顺序保留项目。 List会在开头的常量时间附加元素(::创建一个全新的列表),而ListBuffer#+=将在追加时创建一个节点它在列表的末尾。

使用ListListBuffer之间应该存在很少或没有性能差异,也没有内存占用差异 - 内部这些是相同的数据结构。唯一的问题是你需要reverse最后的列表 - 如果你愿意,这将需要创建第二个列表,所以它可能会更慢。

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

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

对于非常快速的报价到货,您可以考虑使用自定义数据结构 - 对于列表缓冲区,您将支付装箱费用。 但是,如果每秒有5-6个引号并且WINDOW_SIZE100附近,则您不必担心 - 甚至在列表中调用tail缓冲区应该是可以接受的。

答案 1 :(得分:0)

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

  

功能列表的特点是持久性和结构共享,因此在某些情况下可以提供相当大的性能和空间消耗优势。

所以:

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

至于代码:

  • 如果您使用可变结构,您可以删除var,如果要覆盖不可变的结构,请保留它
  • 如果方法返回List而不是操作可变结构或具有全局变量
  • ,那么它将被视为好的样式
  • 如果你在下面的代码片段中处理文件,你不需要关心文件,同时也会同时处理文件

    def processLines(path:String):Unit = for {   line&lt; - Source.fromFile(“GBP_USD_Week1.csv”)。getLines.tail.par   记录&lt; - line.split(“,”) } processRecord(记录)