Andre Queen Andre Queen - 24 days ago 10
Scala Question

Creating a list of ints from a txt file

I have an external list in a txt file, I need to grab the first string and use it as a key, thats fine it works, and then I need a list of the numbers afterwards. However I only get the first, what have I done wrong?
So current output would be SK1, 9 - SK2, 0 etc when I need this to be the full list not just the first number.
I am using Scala on Intelije

/**
* Created by Andre on 10/11/2016.
*/
import scala.io.Source
import scala.io.StdIn.readInt
import scala.io.StdIn.readLine
import scala.collection.immutable.ListMap




object StockMarket extends App{

// APPLICATION LOGIC
// reads the data from text file
val mapdata = readFile("data.txt")
// print data to check it's been read in correctly
println(mapdata)


// *******************************************************************************************************************
// UTILITY FUNCTIONS

// reads data file - comma separated file
def readFile(filename: String): Map[String, Int] = {
// create buffer to build up map as we read each line
var mapBuffer: Map[String, Int] = Map()
try {
for (line <- Source.fromFile(filename).getLines()) { // for each line
val splitline = line.split(",").map(_.trim).toList // split line at , and convert to List

// add element to map buffer
// splitline is line from file as List, e.g. List(Bayern Munich, 24)
// use head as key
// tail is a list, but need just the first (only in this case) element, so use head of tail and convert to int
mapBuffer = mapBuffer ++ Map(splitline.head -> splitline.tail.head.toInt)

}
} catch {
case ex: Exception => println("Sorry, an exception happened.")
}
mapBuffer
}
}


My external List

SK1, 9, 7, 2, 0, 7, 3, 7, 9, 1, 2, 8, 1, 9, 6, 5, 3, 2, 2, 7, 2, 8, 5, 4, 5, 1, 6, 5, 2, 4, 1
SK2, 0, 7, 6, 3, 3, 3, 1, 6, 9, 2, 9, 7, 8, 7, 3, 6, 3, 5, 5, 2, 9, 7, 3, 4, 6, 3, 4, 3, 4, 1
SK4, 2, 9, 5, 7, 0, 8, 6, 6, 7, 9, 0, 1, 3, 1, 6, 0, 0, 1, 3, 8, 5, 4, 0, 9, 7, 1, 4, 5, 2, 8
SK5, 2, 6, 8, 0, 3, 5, 5, 2, 5, 9, 4, 5, 3, 5, 7, 8, 8, 2, 5, 9, 3, 8, 6, 7, 8, 7, 4, 1, 2, 3
SK6, 2, 7, 5, 9, 1, 9, 8, 4, 1, 7, 3, 7, 0, 8, 4, 5, 9, 2, 4, 4, 8, 7, 9, 2, 2, 7, 9, 1, 6, 9
SK7, 6, 9, 5, 0, 0, 0, 0, 5, 8, 3, 8, 7, 1, 9, 6, 1, 5, 3, 4, 7, 9, 5, 5, 9, 1, 4, 4, 0, 2, 0
SK8, 2, 8, 8, 3, 1, 1, 0, 8, 5, 9, 0, 3, 1, 6, 8, 7, 9, 6, 7, 7, 0, 9, 5, 2, 5, 0, 2, 1, 8, 6
SK9, 7, 1, 8, 8, 4, 4, 2, 2, 7, 4, 0, 6, 9, 5, 5, 4, 9, 1, 8, 6, 3, 4, 8, 2, 7, 9, 7, 2, 6, 6

Answer

Here is your code with minimal changes:

// I split it on two functions just to facilitate testing:
def readFile(filename: String): Map[String, List[Int]] = {
  processInput(Source.fromFile(filename).getLines)
}

def processInput(lines: Iterator[String]): Map[String, List[Int]] = {
  var mapBuffer: Map[String, List[Int]] = Map()
  try {
    for (line <- lines) {
      val splitline = line.split(",").map(_.trim).toList

      // here instead of taking .tail.head, we map over the tail (all numbers):
      mapBuffer = mapBuffer + (splitline.head -> splitline.tail.map(_.toInt))
    }
  } catch {
    case ex: Exception => println("Sorry, an exception happened.")
  }
  mapBuffer
}

And here is a solution, which I believe, is more a idiomatic Scala code:

import scala.util.Try

def processInput(lines: Iterator[String]): Map[String, List[Int]] = {
  Try {
    lines.foldLeft( Map[String, List[Int]]() ) { (acc, line) =>

      val splitline = line.split(",").map(_.trim).toList
      acc.updated(splitline.head, splitline.tail.map(_.toInt))
    }
  }.getOrElse {
    println("Sorry, an exception happened.")
    Map()
  }
}

The differences mainly are

  • not using var
  • not using mutable Map (by the way, you don't need a var to mutate it)
  • using foldLeft to iterate and accumulate the Map instead of for
  • using scala.util.Try instead of try-catch.
Comments