我想建立一个这样的地图:
def one = "one"
def two = "two"
def three = Some("three")
Map[String, String]("one" -> one, "two" -> two, "three" -> three)
这将无法编译,因为方法三返回Option而不是String。 我可以这样做:
Map[String, String]("one" -> one, "two" -> two) ++ three.map(t => Map("three" -> t)).getOrElse(Map.empty[String, String])
现在它只会在列表中添加选项。
但必须有一种更优雅的方式。 (例如,lift-json知道如何在构造JValue时过滤掉Options)。
有什么建议吗? (P.S.我在这里简化了问题)
答案 0 :(得分:7)
Map("one" -> one, "two" -> two) ++ three.map("three" -> _)
也可以。
答案 1 :(得分:4)
您有两种地图,例如:
val map1 = Map("one" -> 1, "two" -> 2)
val map2 = Map("three" -> Some(3), "four" -> None)
你可以解包后者:
map2.collect { case (k,Some(v)) => (k,v) }
并合并地图:
map1 ++ map2.collect{ case (k,Some(v)) => (k,v) }
答案 2 :(得分:2)
如果你知道哪些值是选项而哪些不是,你只需在方法调用后直接调用getOrElse
:
Map[String, String]("one" -> one, "two" -> two, "three" -> three.getOrElse("empty"))
如果您不知道哪些方法会返回一个Option,您可以使用隐式转换从Option中提取值,或者如果它是None
则将其设置为默认值:
implicit def optToStr(a : Option[String]) : String = a.getOrElse("empty")
Map[String, String]("one" -> one, "two" -> two, "three" -> three)
之后您也可以使用地图上的过滤器删除默认键值对,尽管这不是很优雅(在这种情况下可能有其他人知道更好的解决方案)。
答案 3 :(得分:0)
为了给您的客户提供一个很好的界面,您可以扩展其中一个Map
来执行解包:
class MyMap[A, B](private val tuples: (A, Option[B])*)
extends collection.DefaultMap[A, B] {
private val container =
new collection.mutable.HashMap[A, B]()
container ++= tuples collect {case (k, Some(v)) => (k, v)}
def iterator = container.iterator
def get(id: A) = container.get(id)
override def size = container.size
}
将此与隐式相结合,将成对(A, B)
转换成对(A, Option[B])
:
implicit def pairToPairWithSomeValue[A, B](t: (A, B)): (A, Option[B]) =
(t._1, Some(t._2))
并将其用作:
def one = "one"
def two = "two"
def three = Some("three")
def four = None
val mm = new MyMap("one" -> one, "two" -> two, "three" -> three,
"four" -> four)
mm foreach println
/* (two,two), (one,one), (three,three) */