我有一个字符串序列Seq[String]
,表示stdin输入行。
这些行映射到模型实体,但不保证1行= 1个实体实例。
每个实体都用一个特殊字符串分隔,该字符串不会出现在输入中的任何其他位置。
我的解决方案如下:
val entities = lines.mkString.split(myDelimiter).map(parseEntity)
parseEntity
实现不相关,它获取一个String并映射到表示模型实体的案例类
问题在于给定的输入,我在lines.mkString
上得到OutOfMemoryException。折叠/ foldLeft / foldRight会更有效吗?或者你有更好的选择吗?
答案 0 :(得分:2)
您可以使用akka流和分隔符框架来解决此问题。有关基本方法,请参阅文档的this section。
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{Framing, Source}
import akka.util.ByteString
val example = (0 until 100).mkString("delimiter").grouped(8).toIndexedSeq
val framing = Framing.delimiter(ByteString("delimiter"), 1000)
implicit val system = ActorSystem()
implicit val mat = ActorMaterializer()
Source(example)
.map(ByteString.apply)
.via(framing)
.map(_.utf8String)
.runForeach(println)
与ByteString之间的转换有点烦人,但Framing.delimiter仅为ByteString定义。
如果您使用更纯粹的功能方法,fs2也会提供原语来解决这个问题。
答案 1 :(得分:0)
如果你正在从一个小溪中读书,那对我有用的东西(你的里程可能会有所不同)。 Scala LineIterator
的略微修改版本:
class EntityIterator(val iter: BufferedIterator[Char]) extends AbstractIterator[String] with Iterator[String] {
private[this] val sb = new StringBuilder
def getc() = iter.hasNext && {
val ch = iter.next
if (ch == '\n') false // Replace with your delimiter here
else {
sb append ch
true
}
}
def hasNext = iter.hasNext
def next = {
sb.clear
while (getc()) { }
sb.toString
}
}
val entities =
new EnityIterator(scala.io.Source.fromInputStream(...).iter.buffered)
entities.map(...)