Edward J. Stembler
Edward J. Stembler

Reputation: 2052

How to find a map in list of maps where a key has a certain value in Scala?

I have a List[Map[String, Any] and I want to return the map which has a certain value for one of the keys. Here's an obfusticated example:

val items: List[Map[String, Any]] = List(Map("name" -> "A", "size" -> 50), Map("name" -> "B", "size" -> 75), Map("name" -> "C", "size" -> 100)))

val mapB: Map[String, Any] = items.find(|m| m("name") == "B") // Psuedo code

mapB would be Map("name" -> "B", "size" -> 75).

Bonus Question

Is there also a way to return the value of another key instead of the whole Map?

For example, if I only wanted the size value (75) for name B? I know I can extract it from the Map as a two-step operation, but if there's another more idiomatic way, I'd be interested in learning it.

Thanks!

Upvotes: 1

Views: 777

Answers (2)

jwvh
jwvh

Reputation: 51271

find() returns an Option in case what you're looking for cannot be found.

val mapB: Option[Map[String, Any]] = items.find(_("name") == "B") //safe

or

val mapB: Map[String, Any] = items.find(_("name") == "B").get //unsafe, might throw

To retrieve the size value from the first Map where "name" -> "B" you could do something like this.

val sz :Any = items.find(m => m.get("name").contains("B")
                           && m.get("size").nonEmpty).fold(0:Any)(_("size"))

Note that sz is type Any because that's what the type of the Map values. Which means that you'd have to cast it (discouraged) to type Int before you can do anything useful with it.

Avoid type Any. It's a sure sign that you're going in the wrong direction.

Upvotes: 2

Complementing jwvh's answers (and using Tim's suggestion to improve safety).
Here is a function that addresses your bonus question.

def findAndGet(maps: List[Map[String, Any]], condition: (String, Any), key: String): Option[Any] = condition match {
  case (k, v) =>
    maps.find(map => map.get(k).contains(v)).flatMap(map => map.get(key))
}
findAndGet(maps = items, condition = ("name", "B"), key = "size")
// res0: Option[Any] = Some(75)

BTW, a Map[String, Any] makes me thing you are dealing with JSONs, have you take a look to any of the Scala libraries for dealing with them in a more "typesafe" way?, having an Any in your code should always be an alarm that something is wrong.

Upvotes: 1

Related Questions