从列表选项创建映射

时间:2014-06-27 01:39:18

标签: scala list-comprehension

我正在尝试从列表选项中创建地图。所以,我有一个像这样声明的列表选项:

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

我希望得到这样的地图:(a - > a,b - > b,c - > c)。

所以我试过这种方式:

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

但是我收到了这个错误:

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

我哪里做错了?

补充说明:这个选项让我很头疼,但我需要了解如何在任何情况下处理它。无论如何,仅仅为了比较,我尝试通过删除选项来消除头痛因素。

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)

所以,显然它有效。这有什么区别?

附加说明:

在这里看起来像“for comprehension”的游戏规则:如果它产生了某些东西,那些东西必须与外部集合的类型相同(在这种情况下是authHeaders,这是一个选项[?] )。如何解决它?

谢谢! 拉嘎

1 个答案:

答案 0 :(得分:8)

问题

你的for被玷污了:

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

本例中的问题是使用flatMap,因为authHeadersOption
让我们来看看签名。 (http://www.scala-lang.org/api/2.11.1/index.html#scala.Option

final def flatMap[B](f: (A) ⇒ Option[B]): Option[B]

因此,函数f应返回Option。但authHeaders.map(header => header -> header)不是Option,因此您会收到错误。

解决方案

假设如果authHeadersNone,您想要一个空的Map,我们可以使用fold

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

如果authHeadersNone,则第一个参数是结果。第二个应该是一个函数Set[String] => Map[String, String],如果有Set,则会对其进行评估。

如果您希望将结果保留在Option中,并且只想在实际存在Map时获得Set,则可以使用map

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

关于您的附加说明

这是flatMapTraversableOnce的签名。 (http://www.scala-lang.org/api/2.11.1/index.html#scala.collection.TraversableOnce

def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): TraversableOnce[B]

此处f可以返回任何GenTraversableOnce实例的集合。

所以这样的事情是可能的:Set(1,2,3).flatMap(i => List(i))(不是真正的创意例子,我知道......)

我认为Option是一个特例。