Create a map from the list of options

I am trying to create a map from a list option. So, I have a list option declared as follows:

val authHeaders: Option[Set[String]] = Some(Set("a", "b", "c"))

and I want to get such a map: (a β†’ a, b β†’ b, c β†’ c).

So, I tried this way:

 for { headers <- authHeaders header <- headers } yield (header -> header) 

But I get this error:

 <console>:11: error: type mismatch; found : scala.collection.immutable.Set[(String, String)] required: Option[?] header <- headers ^ 

Where am I wrong?

Additional note: this Option thing gave me a pretty big headache, but I need to figure out how to handle it anyway. In any case, just for comparison, I tried to remove the headache factor by deleting the option.

 scala> val bah = Set("a", "b", "c") bah: scala.collection.immutable.Set[String] = Set(a, b, c) scala> ( | for { | x <- bah | } yield (x -> x)).toMap res36: scala.collection.immutable.Map[String,String] = Map(a -> a, b -> b, c -> c) 

So this seems to work. What is the difference?

Note:

Looks like a β€œfor understanding” game rule here: if it produces something, something must be of the same type of external collection (in this case it is authHeaders, which is an option [?]). How to get around this?

Thanks !, Raka

+6
source share
1 answer

Problem

Your for gets desugared in:

 authHeaders.flatMap(headers => headers.map(header => header -> header)) 

The problem in this case is to use flatMap because authHeaders is Option .
Let's look at the signature. ( http://www.scala-lang.org/api/2.11.1/index.html#scala.Option )

 final def flatMap[B](f: (A) β‡’ Option[B]): Option[B] 

So, the function f is expected to return Option . But authHeaders.map(header => header -> header) not Option , and therefore you get an error.

Decision

Assuming that if authHeaders is None , you need an empty Map , we can use fold .

 authHeaders.fold(Map.empty[String, String])(_.map(s => s -> s).toMap) 

The first parameter is the result if authHeaders is None . The second is expected to be a Set[String] => Map[String, String] function and will be evaluated if there is some Set .

If you want to store the result in Option and just want to have a Map when there are actually several Set , you can just use Map .

 authHeaders.map(_.map(s => s -> s).toMap) 

Regarding your extra note

This is the signature of flatMap on TraversableOnce . ( http://www.scala-lang.org/api/2.11.1/index.html#scala.collection.TraversableOnce )

 def flatMap[B](f: (A) β‡’ GenTraversableOnce[B]): TraversableOnce[B] 

Here f can return any collection that is an instance of GenTraversableOnce .

So, such things are possible: Set(1,2,3).flatMap(i => List(i)) (not a very creative example, I know ..)

I see Option as a special case.

+8
source

Source: https://habr.com/ru/post/971397/


All Articles