来自测试文件的 Scala 映射

Scala Map from Test File

希望从测试文件创建 Scala 映射。文本文件的示例(其中的几行)如下所示:

Alabama (9),Democratic:849624,Republican:1441170,Libertarian:25176,Others:7312
Alaska (3),Democratic:153778,Republican:189951,Libertarian:8897,Others:6904
Arizona (11),Democratic:1672143,Republican:1661686,Libertarian:51465,Green:1557,Others:475

我得到的地图缓冲区如下:

var mapBuffer: Map[String, List[(String, Int)]] = Map()

请注意,派对值以冒号分隔。

我正在尝试读取文件内容并将数据存储在映射结构中,其中文件的每一行都用于构造一个以日期为键、以元组列表为值的映射条目。结构的类型应该是 Map[String, List[(String,Int)]].

基本上只是试图从文件中创建每一行的地图,但我不太正确。我尝试了下面但没有运气 - 我认为 'val lines' 应该是一个数组而不是迭代器。

val stream : InputStream = getClass.getResourceAsStream("")
      val lines: Iterator[String] = scala.io.Source.fromInputStream(stream).getLines
      var map: Map[String, List[(String, Int)]] = lines
        .map(_.split(","))
        .map(line => (line(0).toString, line(1).toList))
        .toMap

这似乎可以完成这项工作。 (Scala 2.13.x)

val stateVotes =
  util.Using(io.Source.fromFile("votes.txt")){
    val PartyVotes = "([^:]+):(\d+)".r
    _.getLines()
     .map(_.split(",").toList)
     .toList
     .groupMapReduce(_.head)(_.tail.collect{
          case PartyVotes(p,v) => (p,v.toInt)})(_ ++ _)
  } //file is auto-closed

//stateVotes: Try[Map[String,List[(String, Int)]]] = Success(
// Map(Alabama (9) -> List((Democratic,849624), (Republican,1441170), (Libertarian,25176), (Others,7312))
//   , Arizona (11) -> List((Democratic,1672143), (Republican,1661686), (Libertarian,51465), (Green,1557), (Others,475))
//   , Alaska (3) -> List((Democratic,153778), (Republican,189951), (Libertarian,8897), (Others,6904))))

在这种情况下,州名后面的数字将被保留。这可以改变。

不,迭代器很好(实际上比列表好), 您只需要也拆分值即可创建这些元组。

    lines
      .map(_.split(","))
      .map { case l => 
         l.head -> l.tail.toList.map(_.split(":"))
                     .collect { case Seq(a,b) => a -> b.toInt }
      }
      .toMap

一种在我看来更美观的替代方法是尽早转换为地图,然后使用 mapValues(我个人非常喜欢 更喜欢短的 lambdas)。缺点是 mapValues 是懒惰的,所以你最终 最后必须执行 .toMap 两次才能强制执行:

   lines
     .map(_.split(","))
     .map { case l => l.head -> l.tail.toList }
     .toMap
     .mapValues(_.split(":"))
     .mapValues(_.collect { case Seq(a,b) => a -> b.toInt })
     .toMap