scala quirky在这个while循环代码中

时间:2011-07-21 00:23:53

标签: scala

昨天,这段代码让我头疼。我通过逐行读取文件来修复它。有什么想法吗?

即使文件中的行数不大于1,while循环也似乎永远不会被执行。

 val lines = Source.fromFile( new File("file.txt") ).getLines;

 println( "total lines:"+lines.size );

 var starti = 1;
 while( starti < lines.size ){
   val nexti = Math.min( starti + 10, lines.size  );

   println( "batch ("+starti+", "+nexti+") total:" + lines.size )
   val linesSub = lines.slice(starti, nexti)
   //do something with linesSub
   starti = nexti
 }

4 个答案:

答案 0 :(得分:14)

这确实很棘手,我甚至会说它是Iterator中的一个错误。 getLines会返回Iterator懒惰的内容。所以似乎发生的事情是,如果你要求lines.size,迭代器会遍历整个文件来计算行数。之后,它“筋疲力尽”:

scala> val lines = io.Source.fromFile(new java.io.File("....txt")).getLines
lines: Iterator[String] = non-empty iterator

scala> lines.size
res4: Int = 15

scala> lines.size
res5: Int = 0

scala> lines.hasNext
res6: Boolean = false

您会看到,当您执行size两次时,结果为零。

有两种解决方案,要么将迭代器强制为“稳定”,要么lines.toSeq。或者你忘了size并进行“正常”迭代:

while(lines.hasNext) {
  val linesSub = lines.take(10)
  println("batch:" + linesSub.size)
  // do something with linesSub
}

答案 1 :(得分:5)

上述答案都没有达到最佳状态。

Theres是在这里返回Iterator的一个很好的理由。通过延迟,它会从堆中获取压力,然后表示每行的String可以在完成后立即进行垃圾回收。对于大文件,这可以避免OutOfMemoryException。

理想情况下,您可以直接使用迭代器,而不是强制它进入严格的集合类型。

然后使用grouped,根据om-nom-nom的答案:

for (linesSub <- lines grouped 10) {
  //do something with linesSub
}

如果您想保留println计数器,请在索引中压缩:

for ( (linesSub, batchIdx) <- (lines grouped 10).zipWithIndex ) {
  println("batch " + batchIdx)
  //do something with linesSub
}

如果确实需要总数,请两次调用getLines。一次计数,第二次实际处理线。

答案 2 :(得分:4)

第二次调用lines.size时,它返回0.这是因为lines是迭代器,而不是数组。

答案 3 :(得分:4)

我已经以Seq方式重写了您的代码,这是在@ 0__回答中提出的:

val batchSize = 10;
val lines = Source.fromFile("file.txt").getLines.toSeq;

 println( "total lines:"+lines.length);

 var processed = 0;
 lines.grouped(batchSize).foreach( batch => {
      println( "batch ("+processed+","+(processed+Math.min(lines.length-processed,batchSize))+")
               total:"+lines.length
      );
      processed = processed + batchSize;
      //do something with batch
   }
 )