1

Looking to create a scala map from a test file. A sample of the text file (a few lines of it) can be seen below:

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

I have been given the map buffer as follows:

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

Note the party values are separated by a colon.

I am trying to read the file contents and store the data in a map structure where each line of the file is used to construct a map entry with the date as the key, and a list of tuples as the value. The type of the structure should be Map[String, List[(String,Int)]].

Essentially just trying to create a map of each line from the file but I can't quite get it right. I tried the below but with not luck - I think that 'val lines' should be an array rather than an iterator.

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
l0kation
  • 31
  • 6

2 Answers2

2

This appears to do the job. (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))))

In this case the number following the state name is preserved. That can be changed.

jwvh
  • 50,871
  • 7
  • 38
  • 64
  • Do you have any advice on how to make each state a singleton object from the map? Essentially trying to make val arizona = (Democratic,849624).... so that it can be called by an application to display this data - any help would be appreciated! @jwvh – l0kation Mar 31 '21 at 16:42
  • Your terminology is a bit confused. You say you want "_a singleton object_," which would mean `object Arizona {...}`, but then you give an example of `val arizona = ...`, which would be a variable. Then you say "_it can be called by an application_," which indicates a function. My advice is to post a new question with a **clear** description of what you're trying to achieve and an example of how you'd like the client code (the caller) to retrieve the data. – jwvh Mar 31 '21 at 19:46
2

No, iterator is fine (better than list actually), you just need to split the values too to create those tuples.

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

An alternative that looks a little bit more aesthetic to my eye is converting to map early, and then using mapValues (I personally much prefer short lambdas). The downside is mapValues is lazy, so you end up having to do .toMap twice to force it in the end:

   lines
     .map(_.split(","))
     .map { case l => l.head -> l.tail.toList }
     .toMap
     .mapValues(_.split(":"))
     .mapValues(_.collect { case Seq(a,b) => a -> b.toInt })
     .toMap
Dima
  • 39,570
  • 6
  • 44
  • 70