MIkCode
MIkCode

Reputation: 2845

Scala for yield rerun empty List for all the Tuples

I have some issue with this this simple for yield operation.

 for {
        relatedPostMd <- postMd.get.filter(_.fromID == userID)
        nextUrl <- (ch \ "paging" \ "next").asOpt[String] // string
      } yield  (nextUrl, relatedPostMd)

If the result of the filter is none (no match for the filter opration).

Then all the Tuple is empty even though im sure that there is value in nextUrl .

the complete method

 def getPostMD(userID: String, url: String): Future[List[(String, PostMD)]] = {


    val chunk: Future[JsValue] = Methods.getJsonValue(url)

    chunk.map(ch => {
      val postMd: Option[List[PostMD]] = (ch \ "data").asOpt[List[PostMD]]

      for {
        relatedPostMd <- postMd.get.filter(_.fromID == userID)
        nextUrl <- (ch \ "paging" \ "next").asOpt[String]
      } yield  (nextUrl, relatedPostMd)
    })

  }

thanks,

miki

Upvotes: 0

Views: 710

Answers (2)

user5102379
user5102379

Reputation: 1512

May be you need something like this:

val postMd: Option[List[Int]] = ???
val next: Option[String] = ???

val defaultPostMd = -1
val defaultNext = ""
val nextVals = next.toList

val res = postMd
  .getOrElse(Nil)
  .filter(_ % 2 == 1) // << your filter
  .zipAll(nextVals, defaultPostMd, nextVals.lift(0).getOrElse(defaultNext))

1)

val postMd: Option[List[Int]] = Some(List(1, 2, 3, 4, 5))
val next: Option[String] = Some("next")

List((1,next), (3,next), (5,next))

2)

val postMd: Option[List[Int]] = None
val next: Option[String] = Some("next")

List((-1,next))

3)

val postMd: Option[List[Int]] = Some(List(1, 2, 3, 4, 5))
val next: Option[String] = None

List((1,), (3,), (5,))

4)

val postMd: Option[List[Int]] = None
val next: Option[String] = None

List()

Upvotes: 0

Dima
Dima

Reputation: 40510

for comprehension is sugar for flatMap. So, your code is basically equivalent to this:

postMd.get.filter(_.fromID == userID).map { relatedPostMd => 
   x
}

Obviously, when list, returned by filter is empty, the .map produces an empty list as a result. If you want some special handling for that case, you first of all need to decide what you want the second element of the tuple to be (and how many tuples you want to return) when there are no matches. Then you could do something like this:

postMd.get.filter(_.fromID == userID) match {
   case Nil => List(whateverYourSentinelValueIs)
   case x => x
}.map { relatedPostMd => 
    ((ch \ "paging" \ "next"), relatedPostMd)
}

Upvotes: 1

Related Questions