【问题标题】:How to parse the file in a functional way if the iteration needs some state如果迭代需要某种状态,如何以功能方式解析文件
【发布时间】:2014-10-16 13:40:11
【问题描述】:

我有一个 txt 文件,其中包含由“first:”、“second:”和“third:”分隔的 3 个部分,所有这三个部分都将被解析为案例类 Command。

文件格式:

first:
blablabla
blablabla
blablabla

second:
second details blablabla

third:
third details blablabla

案例类Command

case class Command(first: Array[String],
                   second: Array[String],
                   third: Array[String])

当我使用 scalaz 流对其进行迭代时,我需要实现命令式代码和可变数据以在 map 方法中对其进行处理。另外,我需要一个状态值,它可以告诉迭代器哪一行应该放入哪个 ListBuffer。

val firstListBuffer = new ListBuffer[String]
val secondListBuffer = new ListBuffer[String]
val thirdListBuffer = new ListBuffer[String]

var parsingState = ""

io.linesR("testdata/fahrenheit.txt")
    .filter(s => !s.trim.isEmpty)
    .map(t => {
   //if it is first, parsingState = "first"
   //if parsingState = "first", firstListBuffer += t
   //if it is second, parsingState = "second"
   //if parsingState = "second", secondListBuffer += t
   //if it is third, parsingState = "third"
   //if parsingState = "third", thirdListBuffer += t
})

我只是想知道我应该如何重构这个以使其更具功能性?

在此先感谢

【问题讨论】:

  • 我会考虑编写一个尾递归函数来构建相应的ListBuffer。您可以将command 案例类和parsingState 作为参数传递给您的尾递归函数。
  • 在这种情况下,map 不是正确的工具,因为它不能改变流的“形状”——它只是一个接一个地操作单个元素。您可能想从io.linesR(...).split(_.nonEmpty) 之类的东西开始,或者为单个块编写解析器,您可以使用++ 按顺序组合。
  • 我不熟悉 Scalaz 流,但你想做的看起来很像折叠。

标签: scala functional-programming


【解决方案1】:
abstract class ParsingState
case class First extends ParsingState
case class Second extends ParsingState
case class Third extends ParsingState
case class Command(first:String, second:String, third:String) 

def read(fileName:scala.io.Source):Command = { 
@tailrec
def helper(c:Command) = { 
  val p:ParsingState = //read heading, perform custom logic to assign the correct case class
  val newStrings:String = //read strings after heading, until we hit a new heading, need to return if EOF is hit
  p match { 
    case First => helper(Command(c.first + newStrings,c.second,c.third))
    case Second => helper(Command(c.first,c.second + newStrings, c.third))
    case Third => helper(Command(c.first,c.second,c.third + newStrings))
  } 
}    
helper(Command("","",""))
} 

注意:

我没有通过 scalac 运行它,我在 Stackoverflow 文本框内对其进行编码。我鼓励其他人抄写这段代码,并把它作为一个更好的解决方案,因为它不完整,而且我现在无法访问 Scala 编译器。不过,这个解决方案有一个功能范式。

【讨论】:

    猜你喜欢
    • 2011-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    • 2017-07-06
    • 1970-01-01
    • 2014-04-16
    相关资源
    最近更新 更多