简体   繁体   中英

Scala - Inner map returns value ( not an option of that value )

I have a map of maps (immutable)

private val map = mutable.Map[String, mutable.Map[String, MyObject]]()

and I wonder why

map.get(id).get(name)

returns MyObject while

map.get(id)

returns Option[String, MyObject]]

I want to get Option[MyObject] out of map of maps

In the first case, you use get(id) which returns an Option.

In the second case, you call get first on the option which returns the inner Map and then only you use Map("name") which doesn't return an option but the actual value (this is the apply method of Map).

You're actually not calling get(name) but get and then (name) .

scala> Map("id" -> Map("name" -> 5)).get("id")
res8: Option[scala.collection.immutable.Map[String,Int]] = Some(Map(name -> 5))

scala> Map("id" -> Map("name" -> 5)).get("id").get
res9: scala.collection.immutable.Map[String,Int] = Map(name -> 5)

scala> Map("id" -> Map("name" -> 5)).get("id").get("name")
res10: Int = 5

mutable/immutable, same reasoning.


Thus to keep your initial way of doing (for the demonstration):

scala> Map("id" -> Map("name" -> 5)).get("id").get.get("name")
res11: Option[Int] = Some(5)

But this doesn't handle the case of id not being part of the first level Map.

The alternative would be:

Map("id" -> Map("name" -> 5)).get("id").flatMap(_.get("name"))

which performs the get on the value of the inner Map only if the value for id is not None .

In case you would have more levels of nesting of Maps this could become another viable alternative:

for {
  v1 <- Map("id" -> Map("name" -> 5)).get("id");
  v2 <- v1.get("name")
} yield v2

.get(id) is the safe version of trying to get the value from a key in a map rather than map(id) which is the same as .map.apply(id) which does not return an Option.

To get what you want, Option[MyObject] , you will have to call .get(id) then call flatMap on the resulting Option[mutable.Map[String, MyObject]]

private val map = mutable.Map[String, mutable.Map[String, MyObject]]()
val id = "id"
val name = "name"
val thng: Option[MyObject] = map.get(id).flatMap { innerMap =>
  innerMap.get(name)
}

Shorthand: map.get(id).flatMap(_.get(name)) // returns Option[MyObject]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM