rgwozdz
rgwozdz

Reputation: 1143

Scala Nested HashMaps, how to access Case Class value properties?

New to Scala, continue to struggle with Option related code. I have a HashMap built of Case Class instances that themselves contain hash maps with Case Class instance values. It is not clear to me how to access properties of the retrieved Class instances:

import collection.mutable.HashMap

case class InnerClass(name: String, age: Int)
case class OuterClass(name: String, nestedMap: HashMap[String, InnerClass])

// Load some data...hash maps are mutable
val innerMap = new HashMap[String, InnerClass]()
innerMap += ("aaa" -> InnerClass("xyz", 0))

val outerMap = new HashMap[String, OuterClass]()
outerMap += ("AAA" -> OuterClass("XYZ", innerMap))

// Try to retrieve data
val outerMapTest = outerMap.getOrElse("AAA", None)
val nestedMap = outerMapTest.nestedMap

This produces error: value nestedMap is not a member of Option[ScalaFiddle.OuterClass]

// Try to retrieve data a different way
val outerMapTest = outerMap.getOrElse("AAA", None)
val nestedMap = outerMapTest.nestedMap

This produces error: value nestedMap is not a member of Product with Serializable

Please advise on how I would go about getting access to outerMapTest.nestedMap. I'll eventually need to get values and properties out of the nestedMap HashMap as well.

Upvotes: 0

Views: 1062

Answers (5)

Ramesh Maharjan
Ramesh Maharjan

Reputation: 41957

A HashMap will return None if a key is not found so it is unnecessary to do getOrElse to return None if the key is not found.

A simple solution to your problem would be to use get only as below

Change your first get as

val outerMapTest = outerMap.get("AAA").get

you can check the output as

println(outerMapTest.name)
println(outerMapTest.nestedMap)

And change the second get as

val nestedMap = outerMapTest.nestedMap.get("aaa").get

You can test the outputs as

println(nestedMap.name)
println(nestedMap.age)

Hope this is helpful

Upvotes: 1

jwvh
jwvh

Reputation: 51271

Here are some steps you can take to get deep inside a nested structure like this.

outerMap.lift("AAA")             // Option[OuterClass]
        .map(_.nestedMap)        // Option[HashMap[String,InnerClass]]
        .flatMap(_.lift("aaa"))  // Option[InnerClass]
        .map(_.name)             // Option[String]
        .getOrElse("no name")    // String

Notice that if either of the inner or outer maps doesn't have the specified key ("aaa" or "AAA" respectively) then the whole thing will safely result in the default string ("no name").

Upvotes: 1

prayagupadhyay
prayagupadhyay

Reputation: 31212

Since you are using .getOrElse("someKey", None) which returns you a type Product (not the actual type as you expect to be OuterClass)

scala> val outerMapTest = outerMap.getOrElse("AAA", None)
outerMapTest: Product with Serializable = OuterClass(XYZ,Map(aaa -> InnerClass(xyz,0)))

so Product either needs to be pattern matched or casted to OuterClass

pattern match example

scala> outerMapTest match { case x : OuterClass => println(x.nestedMap); case _ => println("is not outerclass") }
Map(aaa -> InnerClass(xyz,0))

Casting example which is a terrible idea when outerMapTest is None, (pattern matching is favored over casting)

scala> outerMapTest.asInstanceOf[OuterClass].nestedMap
res30: scala.collection.mutable.HashMap[String,InnerClass] = Map(aaa -> InnerClass(xyz,0))

But better way of solving it would simply use .get which very smart and gives you Option[OuterClass],

scala> outerMap.get("AAA").map(outerClass => outerClass.nestedMap)
res27: Option[scala.collection.mutable.HashMap[String,InnerClass]] = Some(Map(aaa -> InnerClass(xyz,0)))

For key that does not exist, gives you None

scala> outerMap.get("I dont exist").map(outerClass => outerClass.nestedMap)
res28: Option[scala.collection.mutable.HashMap[String,InnerClass]] = None

Upvotes: 1

rogue-one
rogue-one

Reputation: 11577

you can access the nestMap using below expression.

scala> outerMap.get("AAA").map(_.nestedMap).getOrElse(HashMap())
res5: scala.collection.mutable.HashMap[String,InnerClass] = Map(aaa -> InnerClass(xyz,0))

if "AAA" didnt exist in the outerMap Map object then the below expression would have returned an empty HashMap as indicated in the .getOrElse method argument (HashMap()).

Upvotes: 0

Stephen
Stephen

Reputation: 4296

You want

val maybeInner = outerMap.get("AAA").flatMap(_.nestedMap.get("aaa"))
val maybeName = maybeInner.map(_.name)

Which if your feeling adventurous you can get with

val name: String = maybeName.get

But that will throw an error if its not there. If its a None

Upvotes: 0

Related Questions