2012-07-10 17 views
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]) 

現在只會選項添加到列表中時,它的一些。

但是必須有更優雅的方式。 (舉例來說,在構建JValue時,lift-json知道如何過濾選項)。

有什麼建議嗎? (P.S.我已經簡化了這裏的問題)

+1

也許如果你解釋你的目的。 'String'和'Option [String]'顯然是兩種不同的類型,所以你不清楚爲什麼你要能夠添加到'Map'中。 – 2012-07-10 15:52:06

+0

它用於構建具有「真實」值和選項值(提取)的映射的目的,但僅當它們是某些(而不是無)時。 – Albert 2012-07-10 16:13:28

+0

如果三個返回None,它是否仍然需要添加到地圖? – Brian 2012-07-10 17:21:19

回答

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) */ 
+0

謝謝,這個工程。我很善良 - 希望這可以隱藏在某個地方的藏品中,但我想不是。 – Albert 2012-07-11 08:00:26

7

Map("one" -> one, "two" -> two) ++ three.map("three" -> _)也可以工作。

+0

我用這個解決方案,足夠簡單。我將@mhs的答案標記爲解決方案,因爲對於面臨相同問題的其他人而言,這更爲優雅和有用。 – Albert 2012-07-11 08:03:12

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) 

您還可以通過使用過濾器在地圖上雖然這是刪除默認的鍵值對後不是很elega nt(也許別人知道在這種情況下更好的解決方案)。

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) }