0

I'm receiving a message from a process which I'm trying to map it with a case class. The message is within the pipe symbols separated by commas like below

|id1,5,2010-06-19,27.40,2010-06-20,35.40,2010-06-21,8.50,2010-06-22,23.40,2010-06-23,57.40,TX5|

The message is packed in this way

1.id

2.number of occurrences of 3 and 4 together

3.date //it repeats along with 4 based on 2

4.amount //it repeats along with 3 based on 2

5.code -- last field

Though there are 5 fields at high level, 3 and 4 can repeat based on 2.

For better understanding, here are some more samples

|id2,7,2010-06-19,56.40,2010-06-20,23.76,2010-06-21,12.50,2010-06-22,87.12,2010-06-23,52.90,2010-06-24,35.70,2010-06-25,72.80,TX3|
|id3,4,2010-06-19,87.40,2010-06-20,32.40,2010-06-21,21.50,2010-06-22,73.40,TX2|
|id4,6,2010-06-19,56.12,2010-06-20,66.43,2010-06-21,23.12,2010-06-22,87.12,2010-06-23,34.90,2010-06-24,55.00,FT3|

I'm able to remove the pipe symbols from beginning and end.. parse and get the first and last fields.

scala> val str="id1,5,2010-06-19,27.40,2010-06-20,35.40,2010-06-21,8.50,2010-06-22,23.40,2010-06-23,57.40,TX5"
str: String = id1,5,2010-06-19,27.40,2010-06-20,35.40,2010-06-21,8.50,2010-06-22,23.40,2010-06-23,57.40,TX5

scala> val (id,code) = (str.split(",")(0), str.split(",").last)
id: String = id1
code: String = TX5

scala>

But how to I map the rest of them to fit into a case class?.

Note that this is not the same as Scala: Parsing Array of String to a case class where the message has fixed number of columns and can be mapped to case class easily

stack0114106
  • 8,534
  • 3
  • 13
  • 38
  • this question is not same as https://stackoverflow.com/questions/53516233/scala-parsing-array-of-string-to-a-case-class.. in that the Array is linear and fixed size – stack0114106 Nov 28 '18 at 18:47

1 Answers1

1

You haven't specified what the case class should look like. Here's an approach that is reasonably tolerant of any poorly formatted input data strings.

case class CC(id        :String
             ,datePrice :Seq[(String,Double)]
             ,code      :String)

import util.Try
def mkCC(dataStr :String) :CC = {
  val dataArr = dataStr.split(",")
  val id      = dataArr.head.filter('|'.!=)
  val code    = dataArr.last.filter('|'.!=)
  val dps     = Try{
    val len = dataArr(1).toInt
    Seq.range(2, len*2+2, 2)
       .flatMap(idx => Try{(dataArr(idx),dataArr(idx+1).toDouble)}.toOption)
  }.getOrElse(Seq())
  CC(id, dps, code)
}

usage:

val data1="|id2,7,2010-06-19,56.40,2010-06-20,23.76,2010-06-21,12.50,2010-06-22,87.12,2010-06-23,52.90,2010-06-24,35.70,2010-06-25,72.80,TX3|"
val data2="|id3,4,2010-06-19,87.40,2010-06-20,32.40,2010-06-21,21.50,2010-06-22,73.40,TX2|"
val data3="|id4,6,2010-06-19,56.12,2010-06-20,66.43,2010-06-21,23.12,2010-06-22,87.12,2010-06-23,34.90,2010-06-24,55.00,FT3|"

val cc1 :CC = mkCC(data1)
val cc2 :CC = mkCC(data2)
val cc3 :CC = mkCC(data3)
jwvh
  • 50,871
  • 7
  • 38
  • 64
  • Great..this solves the parsing... however is it possible to convert the datePrice as a kind of JSON array?.. because I should be able to use the CC something like datePrice.date[0] or datePrice.Price[1]..not with ._1, ._2... – stack0114106 Nov 28 '18 at 23:02
  • You could create a separate class in place of the tuple, `DatePrice(date:String, price:Double)`. Access might be something like `cc3.pds(4).date` and `cc9.pds(0).price`. Or you might choose to load two separate arrays. Access would look like `cc2.date(5)` and `cc1.price(6)`. Either way, the parsing/loading code wouldn't be much different from the presented coding example. – jwvh Nov 29 '18 at 02:13