繁体   English   中英

更具功能性的实现?

[英]A more Functional implementation?

下面的方法只是解析一个ID为DATE,NUMBER的CSV文件。

有没有这样的实现更实用-尤其是一些不使用可变集合并返回不可变集合的实现? 此后我拥有的所有代码都不需要数据结构中的可变性。

我显然不想使代码变得比以前更加低效或丑陋-但是我很想知道一个功能更强大的编程工程师是否会以不同的方式来做?

def parseFile() : HashMap[String,ListBuffer[String]] = {

   val userDataSet = scala.collection.mutable.HashMap.empty[String,ListBuffer[String]]

   for ( ln <- io.Source.stdin.getLines ) {

      val cols = ln.split(",")
      var values : ListBuffer[String] = userDataSet.getOrElse( cols(0), null )
      if ( values == null ) {
         values = ListBuffer.empty[String]
         userDataSet( cols( 0 ) ) = values
      }

      values += cols(2)
   }

   HashMap[String,ListBuffer[String]]() ++ userDataSet
}

首先,让我们修复您已经拥有的东西:

def parseFile(): Map[String, ListBuffer[String]] = { // always use interfaces (Map, not HashMap)
  val userDataSet = scala.collection.mutable.HashMap.empty[String, ListBuffer[String]]
  for (ln <- io.Source.stdin.getLines) {
    val Array(id, date, number) = ln.split(",")  // pattern match with names for clarity
    val values = userDataSet.getOrElseUpdate(id, ListBuffer.empty)
    values += number
  }
  userDataSet.toMap
}

请注意,即使没有getOrElseUpdate ,您仍然希望通过简单地执行!userDataSet.contains(id)来避免返回null和检查事件。 另外,您可以使用.get(id) ,它返回Option

现在为功能解决方案。 当您想遍历其他集合来构建一个集合时,您可能需要“折叠”:

def parseFile(): Map[String, Vector[String]] = {
  val lines = io.Source.stdin.getLines
  lines.foldLeft(Map.empty[String, Vector[String]]) { (userDataSet, ln) =>
    val Array(id, date, number) = ln.split(",")  // pattern match with names for clarity
    val existingValues = userDataSet.getOrElse(id, Vector.empty)
    val updatedValues = existingValues :+ number
    userDataSet + (id -> updatedValues)         // update the Map with the new key/value
  }
}

如果您想“超级功能化”,可以使用scalaz-stream( https://github.com/scalaz/scalaz-stream )做到。

完整的要旨在这里: https : //gist.github.com/ezhulenev/9966059

要了解runFoldMap,您还需要看一下Monoid概念: http ://eed3si9n.com/learning-scalaz/Monoid.html。 (地图为monoid,矢量为monoid,矢量地图也为monoid)

val csv =
"""|0,2014-01-01,1
   |0,2014-01-02,2
   |1,2014-01-01,3
   |1,2014-01-01,4""".stripMargin

val is = new ByteArrayInputStream(csv.getBytes)

val process = io.linesR(is).
  map(_.split(",")).               // split to columns
  map(arr => (arr(0), arr(2))).    // pick id & number columns
  runFoldMap { case (id, number) => Map(id -> Vector(number)) }

val output: Map[String, Vector[String]] = process.run
println(s"Output: ")
output.foreach(println)

输出:

(1,Vector(3, 4))
(0,Vector(1, 2))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM