我有一个名为“mappings.txt”的文件格式为:
k->v
要将此文件读入地图我使用:
val file = Source.fromFile("mappings.txt").getLines.filter(f => !f.trim.isEmpty)
val map = file.map(m2 => (m2.split("->")(0), m2.split("->")(1))).toMap
如何将文件读入多个行中出现值的Map? 但是一些映射值超过了多行:例如:
k -> v \n
test
\n here
k2 -> v2
答案 0 :(得分:3)
下面是尾递归函数,它将以指定的方式对输入行进行分组。
这个想法很简单:逐行处理输入。遇到$ tclsh ~/tmp/2.tcl
can't read "errorCode": no such variable
while executing
"puts "errorCode=$errorCode""
(procedure "p1" line 3)
invoked from within
"p1"
(file "~/tmp/2.tcl" line 9)
对时,将其添加到缓冲区(或累加器)。当行看起来不像key->value
对时,将此行添加到缓冲区中已存在的最后一对的值字符串中。
k->v
结果:
val s =
"""k -> v \n
| test
| \n here
|k2 -> v2
""".stripMargin.split("\n").toList
def rec(input:List[String]):Map[String, String] = {
val ARROW = "\\s*(.+?)\\s*->\\s*(.+?)\\s*".r
def r0(in:List[String], accum:List[(String, List[String])]):List[(String, List[String])] = in match {
// end of input, reverse line accumulators
case Nil => accum.map{case (k, lines) => k -> lines.reverse}.reverse
// key -> value line encountered, adding new k->v pair to outer accumulator
case ARROW(k, v) :: tail => r0(tail, (k, List(v)) :: accum)
// line without key encountered, adding this line to previous k->v pair in the accumulator
case line :: tail => r0(tail, accum match {
case (k, lines) :: accTail => (k, line :: lines) :: accTail
case _ => accum // if accum is empty and input doesn't have a key, ignore line
})
}
r0(input, Nil).toMap.mapValues(_.mkString("\n"))
}
rec(s).foreach(println(_))
每行只处理一次,缓冲区的每次加法和修改都是O(1),所以整个过程都是O(N)。
另外,请注意,您正在以放弃资源的方式阅读文件。请参阅Tables.toTable
。
答案 1 :(得分:1)
这似乎对我有用,因为测试数据非常有限。
val myMap = io.Source
.fromFile("junk.txt") // open the file
.mkString // turn it into one long String
.split("(?=\\n\\S+\\s*->)") // a non-consuming split
.map(_.trim.split("\\s*->\\s*")) // split each element at "->"
.map(arr => (arr(0)->arr(1))) // from 2-element Array to tuple
.toMap // from tuple to k->v pair
结果:
scala> myMap("k")
res0: String =
v \n
test
\n here
scala> myMap("k2")
res1: String = v2