将文件读入Map

时间:2017-05-27 00:17:20

标签: scala

我有一个名为“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

2 个答案:

答案 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