来自文件的可重用流
Reusable streams from file
如何在 Scala 中从文件创建可重用流?我有一个很大的文件,我想多次使用它的内容,但是我可能不需要完整地读取整个文件
我试过类似的方法,但没有成功,
// file iterator
val f = Source.fromFile("numberSeq.txt").getLines
// construct stream from file iterator
def numSeq: Stream[BigInt] = Stream.cons(BigInt(f.next()),numSeq)
//test
numSeq take 5 foreach println
numSeq take 5 foreach println //the stream continues to print next file lines instead of going back to the first line
最简单的方法是在迭代器上使用 toStream
:
scala> val f = List(1,2,3,4,5,6,7,8,9,10).toIterator.toStream
f: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> f take 5 foreach println
1
2
3
4
5
scala> f take 5 foreach println
1
2
3
4
5
在您的具体案例中,问题是您在每次 numSeq
调用时都有全新的流,因为使用 def
而不是 val
。你仍然需要def
进行递归定义,但不要忘记在使用前将其保存到val
:
scala> def numSeq: Stream[BigInt] = Stream.cons(BigInt(f.next()),numSeq)
numSeq: Stream[BigInt]
scala> val numSeq1 = numSeq
numSeq1: Stream[BigInt] = Stream(1, ?)
scala> numSeq1 take 5 foreach println
1
2
3
4
5
scala> numSeq1 take 5 foreach println
1
2
3
4
5
错误用法示例(注意numSeq
而不是numSeq1
):
scala> numSeq take 5 foreach println
6
7
8
9
10
scala> numSeq take 5 foreach println
java.util.NoSuchElementException: next on empty iterator
at scala.collection.Iterator$$anon.next(Iterator.scala:39)
at scala.collection.Iterator$$anon.next(Iterator.scala:37)
at scala.collection.LinearSeqLike$$anon.next(LinearSeqLike.scala:59)
at .numSeq(<console>:14)
... 33 elided
顺便说一句,cons
有更可爱的 #::
语法:
import Stream._
def numSeq: Stream[BigInt] = BigInt(f.next()) #:: numSeq
val numSeq1 = numSeq
最后是封装性更好的版本:
val numSeq = {
def numSeq: Stream[BigInt] = BigInt(f.next()) #:: numSeq
numSeq
}
如何在 Scala 中从文件创建可重用流?我有一个很大的文件,我想多次使用它的内容,但是我可能不需要完整地读取整个文件
我试过类似的方法,但没有成功,
// file iterator
val f = Source.fromFile("numberSeq.txt").getLines
// construct stream from file iterator
def numSeq: Stream[BigInt] = Stream.cons(BigInt(f.next()),numSeq)
//test
numSeq take 5 foreach println
numSeq take 5 foreach println //the stream continues to print next file lines instead of going back to the first line
最简单的方法是在迭代器上使用 toStream
:
scala> val f = List(1,2,3,4,5,6,7,8,9,10).toIterator.toStream
f: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> f take 5 foreach println
1
2
3
4
5
scala> f take 5 foreach println
1
2
3
4
5
在您的具体案例中,问题是您在每次 numSeq
调用时都有全新的流,因为使用 def
而不是 val
。你仍然需要def
进行递归定义,但不要忘记在使用前将其保存到val
:
scala> def numSeq: Stream[BigInt] = Stream.cons(BigInt(f.next()),numSeq)
numSeq: Stream[BigInt]
scala> val numSeq1 = numSeq
numSeq1: Stream[BigInt] = Stream(1, ?)
scala> numSeq1 take 5 foreach println
1
2
3
4
5
scala> numSeq1 take 5 foreach println
1
2
3
4
5
错误用法示例(注意numSeq
而不是numSeq1
):
scala> numSeq take 5 foreach println
6
7
8
9
10
scala> numSeq take 5 foreach println
java.util.NoSuchElementException: next on empty iterator
at scala.collection.Iterator$$anon.next(Iterator.scala:39)
at scala.collection.Iterator$$anon.next(Iterator.scala:37)
at scala.collection.LinearSeqLike$$anon.next(LinearSeqLike.scala:59)
at .numSeq(<console>:14)
... 33 elided
顺便说一句,cons
有更可爱的 #::
语法:
import Stream._
def numSeq: Stream[BigInt] = BigInt(f.next()) #:: numSeq
val numSeq1 = numSeq
最后是封装性更好的版本:
val numSeq = {
def numSeq: Stream[BigInt] = BigInt(f.next()) #:: numSeq
numSeq
}