Kumar Padhy
Kumar Padhy

Reputation: 101

What is the scala way of extracting value from Option[String]?

i am trying to extract aid and event_type from Option[String] what is the best scala way to extract those values and if not there get null as output.

val payload = Some({"event":"testApi",
    "data":[{"aid":"test","pr":"{\"id\":\"813da0e5-d9aa-4275-b9d4-5e84362b73bb\",\"event_type\":\"promo app loaded\",\"label\":\"beach apartheid\",\"total\":1,\"timestamp\":1617891494152}}]",
    "tv":"js-2.17.3"
    })

If I have this how to extract other then if else.

Upvotes: 1

Views: 3954

Answers (2)

Dima
Dima

Reputation: 40500

It depends on what it is you are going to do with this payload afterwards. Option is a monad, and all the standard operations like .map, flatMap, .foreach, .filter, .collect etc. apply to it. I really recommend that you read up on scala monads to get a good handle on it.

In a nutshell, you should structure your code so that you never need to do option.get to access the actual value, almost never do option.isEmpty (or option.nonEmpty, and very rarely if ever do .getOrElse (e.g. val unwrappedJson = payload.getOrElse('{}')).

I would also avoid pattern matching in most cases, despite what that book mentioned in the other answer suggests. It may be "most common", but is not "the best" in most cases (though, this is starting to get into the "personal taste" area, there is nothing technically wrong with pattern matching, except that it is not "monadic" and is therefore somewhat harder to read and parse visually).

Some examples of things you can do:

    def parsePayload(maybePayload: Option[String]): Option[Payload] = 
       maybePayload.map(json.readValue[Payload])
   
    ...
    
    def getLabels(maybePayload: Option[String]): Seq[String] = maybePayload
        .map(json.readValue[Payload])
        .toSeq
        .flatMap(_.data)
        .map(_.pr.label)


    ...

    def uniqueIds(maybePayload: Option[String]): Seq[String] = maybePayload
       .map(json.readValue[Payload])
       .toSeq
       .flatMap(_.data)
       .map(_.pr.id)
       .distinct

    ...


    def maybeData(maybePayload: Option[String]): Seq[Data] = 
       parsePayload(maybePayload)
         .fold(Seq.empty[Data])(_.data)

    ...


    def byId(maybePayload: Option[String]): Map[String, Seq[Data]] = maybePayload
       .map(json.readValue[Payload])
       .toSeq
       .flatMap(_.data)
       .groupBy(_.pr.id)
       .map { case(id, datas) => datas }
       
    def forId(maybePayload: Option[String], id: String): Seq[Data] = maybePayload
       .map(json.readValue[Payload])
       .toSeq
       .flatMap(_.data.filter(_.pr.id == id))
     ...

    def forId2(maybePayload: Option[String], id: String): Seq[Data] = 
       byId(maybePayload).getOrElse(id)

    ...

    def maxTotal(maybePayload: Option[String]): Option((String, Int)) = 
      parsePayload(maybePayload)
      .collect { case Payload(_, data, _) if data.nonEmpty => data.maxBy(_.pr.total) }
      .map { case data => data.pr.id -> data.pr.total }
         
    ...  

 
    def printPayload(maybePayload: Option[String]): Unit = 
       maybePayload.foreach(println)

Etc.

Upvotes: 4

Michael Heil
Michael Heil

Reputation: 18475

According to the book "Programming in Scala, 3rd Edition", published by artima it says:

"The most common way to take optional values apart is through a pattern match."

Example:

def show(x: Option[String]): String = x match {
  case Some(s) => s
  case None => "?"
}

Upvotes: 1

Related Questions