我对这个简单的yield操作有一些问题。
for {
relatedPostMd <- postMd.get.filter(_.fromID == userID)
nextUrl <- (ch \ "paging" \ "next").asOpt[String] // string
} yield (nextUrl, relatedPostMd)
如果过滤器的结果为none(过滤器操作不匹配)。
即使确定 nextUrl 中有值,所有Tuple都是空的。
完整的方法
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)
})
}
感谢,
三木
答案 0 :(得分:1)
for
理解是flatMap
的糖。所以,你的代码基本上等同于:
postMd.get.filter(_.fromID == userID).map { relatedPostMd =>
x
}
显然,当filter
返回的列表为空时,.map
会生成一个空列表。如果你想对这种情况进行一些特殊的处理,你首先需要在没有匹配时决定你想要元组的第二个元素(以及你想要返回多少个元组)。然后你可以做这样的事情:
postMd.get.filter(_.fromID == userID) match {
case Nil => List(whateverYourSentinelValueIs)
case x => x
}.map { relatedPostMd =>
((ch \ "paging" \ "next"), relatedPostMd)
}
答案 1 :(得分:0)
可能你需要这样的东西:
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()