Reputation: 599
I have a map:
val m: Map[List[String], String] = Map (
List("banana", "melon", "apple") -> "fruit",
List("chair", "table", "wardrobe") -> "furniture")
How to check, what is e.g. banana
? This ofc doesn't work:
scala> m("banana")
I could split the lists into single entries String -> String
, but there are lots of them, so I prefer List[String] -> String
.
Upvotes: 0
Views: 123
Reputation: 22206
I could split the lists into single entries
String -> String
, but there are lots of them, so I preferList[String] -> String
.
That doesn't sound like a very good reason to me. The whole point of using a map is easy and quick access to values. Using a list as the key type when you'll be looking up values by elements of that list just makes it hard to use the map, while giving almost no advantages.
I suggest you "flatten" your map, so one key maps to one value with possibly duplicate values:
val m: Map[List[String], String] = Map(
List("banana", "melon", "apple") -> "fruit",
List("chair", "table", "wardrobe") -> "furniture"
)
val flattenedMap = m.flatMap { case (keys, value) =>
keys.map(_ -> value)
}
flattenedMap("banana")
If you're not yet comfortable with using flatMap
, you can use a for-comprehension instead, which works very nicely on this example:
val m: Map[List[String], String] = Map(
List("banana", "melon", "apple") -> "fruit",
List("chair", "table", "wardrobe") -> "furniture"
)
val flattenedMap: Map[String, String] = for {
(keys, value) <- m // for each list of keys and value in your map
key <- keys // and for each key from the list of keys
} yield (key, value) // create a pair of key and value
This yields the same result as the example with flatMap
above.
Or you could just initialize your Map
as a "flattened" map immediately:
val flattenedMap: Map[String, String] = Map(
"banana" -> "fruit",
"melon" -> "fruit",
"apple" -> "fruit",
"chair" -> "furniture",
"table" -> "furniture",
"wardrobe" -> "furniture"
)
flattenedMap("banana")
Upvotes: 2
Reputation: 18864
If it's a one-off lookup, then any lazy (the one that does not create unnecessary container copies) combo would do (I normalized them all to return Option
):
m.withFilter(_._1.contains("banana")).map(_._2).headOption
// or
m.find(_._1.contains("banana")).map(_._2)
// or
(for ((k, v) <- m.toStream if k.contains("banana")) yield v).headOption
Otherwise, if this query needs to run often you might want to change this data structure for faster lookups with
val mm: immutable.Map[String, String] = m.flatMap{ case (k,v) => k.map(_ -> v)}
...
print(mm["banana"])
Upvotes: 0
Reputation: 27065
You could also use this:
map.keys.flatten.exists(s => s == "banana")
The flatten
maps all lists of lists to a single list. exists
checks if banana is in that list.
Upvotes: 0
Reputation: 599
Ok, got it. I can use foreach
to check every key:
m foreach (x => println(x._1.contains("banana")))
Upvotes: 0