I have method with param type Future[List[MyRes]]
. MyRes
has two option fields id
and name
. Now I want to create map of id
and name
if both present. I am able to create map with default value as follow but I don't want to have default value just skip the entry with null value on either.
def myMethod(myRes: Future[List[MyRes]]): Future[Map[Long, String]] = {
myRes.map (
_.map(
o =>
(o.id match {
case Some(id) => id.toLong
case _ => 0L
}) ->
(o.name match {
case Some(name) => name
case _ => ""
})
).toMap)
Any suggestion?
You are looking for collect
:)
myRes.map {
_.iterator
.map { r => r.id -> r.name }
.collect { case(Some(id), Some(name) => id -> name }
.toMap
}
If your MyRes
thingy is a case class, then you don't need the first .map
:
myRes.map {
_.collect { case MyRes(Some(id), Some(name)) => id -> name }
.toMap
}
collect
is like .map
, but it takes a PartialFunction, and skips over elements on which it is not defined. It is kinda like your match
statement but without the defaults.
Update:
If I am reading your comment correctly, and you want to log a message when either field is a None, collect
won't help with that, but you can do flatMap
:
myRes.map {
_.flatMap {
case MyRes(Some(id), Some(name)) => Some(id -> name)
case x => loger.warn(s"Missing fields in $x."); None
}
.toMap
}
Try this:
def myMethod(myRes: Future[List[MyRes]]): Future[Map[Long, String]] = {
myRes.map (
_.flatMap(o =>
(for (id <- o.id; name <- o.name) yield (id.toLong -> name)).toList
).toMap
)
}
The trick is flattening List[Option[(Long,String)]]
by using flatMap
and converting the Option
to a List
.