0
votes

I have a "dirtyMap" which is immutable.Map[String, collection.mutable.Set[String]]. I want to convert dirtyMap to immutable Map[String, Set[String]]. Could you please let me know how to do this. I tried couple of ways that didn't produce positive result

Method 1: Using map function

dirtyMap.toSeq.map(e => {
  val key = e._1
  val value = e._2.to[Set]
  e._1 -> e._2
}).toMap()

I'm getting syntax error

Method 2: Using foreach

dirtyMap.toSeq.foreach(e => {
  val key = e._1
  val value = e._2.to[Set]
  e._1 -> e._2
}).toMap()

cannot apply toMap to output of foreach

Disclaimer: I am a Scala noob if you couldn't tell.

UPDATE: Method 1 works when I remove parenthesis from toMap() function. However, following is an elegant solution

dirtyMap.mapValues(v => v.toSet)

Thank you Gabriele for providing answer with a great explanation. Thanks Duelist and Debojit for your answer as well

3
Also removing parentheses after toMap in Method 1 could help to get rid of syntax error.Duelist

3 Answers

1
votes

You can simply do:

dirtyMap.mapValues(_.toSet)

mapValues will apply the function to only the values of the Map, and .toSet converts a mutable Set to an immutable one.

(I'm assuming dirtyMap is a collection.immutable.Map. In case it's a mutable one, just add toMap in the end)

If you're not familiar with the underscore syntax for lambdas, it's a shorthand for:

dirtyMap.mapValues(v => v.toSet)

Now, your first example doesn't compile because of the (). toMap takes no explicit arguments, but it takes an implicit argument. If you want the implicit argument to be inferred automatically, just remove the ().

The second example doesn't work because foreach returns Unit. This means that foreach executes side effects, but it doesn't return a value. If you want to chain transformations on a value, never use foreach, use map instead.

0
votes

You can use

dirtyMap.map({case (k,v) => (k,v.toSet)})

0
votes

You can use flatMap for it:

dirtyMap.flatMap(entry => Map[String, Set[String]](entry._1 -> entry._2.toSet)).toMap

Firstly you map each entry to immutable.Map(entry) with updated entry, where value is immutable.Set now. Your map looks like this: mutable.Map. And then flatten is called, so you get mutable.Map with each entry with immutable.Set. And then toMap converts this map to to immutable.

This variant is complicated a bit, you simply can use dirtyMap.map(...).toMap as Debojit Paul mentioned.

Another variant is foldLeft:

dirtyMap.foldLeft(Map[String, Set[String]]())(
  (map, entry) => map + (entry._1 -> entry._2.toSet)
)

You specify accumulator, which is immutable.Map and you add each entry to this map with converted Set.

As for me, I think using foldLeft is more effective way.