3

我想建立一个这样的地图:

  def one = "one"
  def two = "two"
  def three = Some("three")

  Map[String, String]("one" -> one, "two" -> two, "three" -> three)

这不会编译,因为方法三返回一个选项而不是字符串。我可以这样工作:

Map[String, String]("one" -> one, "two" -> two) ++ three.map(t => Map("three" -> t)).getOrElse(Map.empty[String, String])

现在它只会在选项为 Some 时将选项添加到列表中。

但一定有更优雅的方式。(例如,lift-json 知道如何在构造 JValue 时过滤掉 Options)。

有什么建议么?(PS我在这里简化了问题)

4

4 回答 4

7

Map("one" -> one, "two" -> two) ++ three.map("three" -> _)也会起作用。

于 2012-07-10T15:57:48.050 回答
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) }
于 2012-07-10T16:37:53.893 回答
2

如果您知道哪些值是选项,哪些不是,您可以简单地getOrElse在方法调用之后直接调用:

Map[String, String]("one" -> one, "two" -> two, "three" -> three.getOrElse("empty"))

如果您不知道哪些方法将返回选项,则可以使用隐式转换从选项中提取值,或者将其设置为默认值(如果是)None

implicit def optToStr(a : Option[String]) : String = a.getOrElse("empty")
Map[String, String]("one" -> one, "two" -> two, "three" -> three)

您也可以在之后通过在地图上使用过滤器来删除默认的键值对,尽管这不是很优雅(在这种情况下,也许其他人知道更好的解决方案)。

于 2012-07-10T15:59:10.980 回答
0

为了为您的客户提供一个很好的界面,您可以扩展其中一个Map's 来执行解包:

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
}

将此与将 pair(A, B)转换为 pairs的隐式结合起来(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) */
于 2012-07-10T19:13:37.000 回答