以下方法只解析一个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
}
答案 0 :(得分:3)
首先,让我们来解决你已经得到的问题:
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-check-check。或者,您可以使用.get(id)
,它会返回Option
。
现在为功能解决方案。当你想通过遍历其他一些集合来建立一个集合时,你可能想要一个&#34; fold&#34;:
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
}
}
答案 1 :(得分:1)
如果你想成为超级功能性的&#34;你可以用scalaz-stream(https://github.com/scalaz/scalaz-stream)来做。
全部要点在这里:https://gist.github.com/ezhulenev/9966059。
要了解runFoldMap,您还需要了解Monoid概念:http://eed3si9n.com/learning-scalaz/Monoid.html。 (地图是幺半群,矢量是幺半群,矢量地图也是幺半群)
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))