Search code examples
scalacsvparsingtreemapcase-class

How to parse a csv with matching case class and store the output to treemap[Int, List[List[InputConfig]] object in scala


I am trying to parse the csv configuration file and store the output in treeMap with type ]>, I am getting an error while implementing it and also looking for various other collections which is easier and flexible to implement my requirement.

I have created a case class for pattern matching for the input csv file and I have used one of the columns in the configuration as key for each of the configuration and if there is more than one configuration is having the same key then the configuration has to be stored as the list of values for each key.

case class InputConfig(A:String,
                       B:String,
                       ID:Int,
                       C:String,
                       D:String,
                       E:Option[String] = None);

var configTree: TreeMap[Int, List[List[InputConfig]]] = null;

def csvFileParser(fileName : String): Unit = {

      for (row <- scala.io.Source.fromFile(fileName).getLines().drop(4)){

        val conf = row.toString.split(",").map(_.trim)
        InputConfig(conf(0),
          conf(1),
          conf(2).toInt,
          conf(3),
          conf(4),
          Some(conf(5)))
        configTree += (conf(2).toInt -> List[List[InputConfig]])
        println(configTree) 



IF the input is as given below

"1","2",1,"4","5","6"
"2","2",2,"4","5","6"
"2","2",2,"4","5","6"
"3","2",3,"4","5","6"
"4","2",4,"4","5","6"
"4","2",4,"4","5","6"

The expected output should be like this

1 -> List("1","2",3,"4","5","6")
2 -> List("2","2",3,"4","5","6"),List("2","2",2,"4","5","6")
3 -> List("2","2",3,"4","5","6")
4 -> List("2","2",3,"4","5","6"),List("4","2",4,"4","5","6")

And I should be able to access each element using the key and the column name mentioned in the case class.
And also should be able to iterate through the collections in for each key.

Solution

  • Here you go:

    import scala.collection.immutable.TreeMap
    
    object CsvParse {
    
      def main(args: Array[String]) = {
        csvFileParser(args(0))
      }
    
    
      var configTree: TreeMap[Int, List[InputConfig]] = TreeMap()
    
      def csvFileParser(fileName: String): Unit = {
    
        for (row <- scala.io.Source.fromFile(fileName).getLines()) {
    
          val conf = row.toString.split(",").map(_.trim)
          val key = conf(2).toInt
          val value = InputConfig(conf(0),
            conf(1),
            key,
            conf(3),
            conf(4),
            Some(conf(4)))
    
          configTree.get(key) match {
            case None => configTree += (key -> List(value))
            case Some(xs) => configTree += (key -> (value :: xs))
          }
        }
    
        println(configTree)
      }
    }
    
    case class InputConfig(A: String,
                           B: String,
                           ID: Int,
                           C: String,
                           D: String,
                           E: Option[String] = None)
    

    If you have sbt installed you can run using

    sbt
    runMain CsvParse input.dat
    

    where input.dat contains your input.

    For something less brittle, you might want to use any of the free CSV parsers for Scala. I would recommend scala-csv-parser from zamblauskas or scala-csv from tototoshi.

    Also, I'm not sure why you want both conf(4) and Some(conf(4)) in your case class. Your code is brittle anyway and will throw an exception if conf(4) is not there. There seems little reason to include Some(conf(4)) in the case class.