2011-10-11 77 views
4

我有一個嵌套的地圖m這就好比:斯卡拉 - 減少/ foldLeft

m = Map("email" -> "[email protected]", "background" -> Map("language" -> "english"))

我有一個數組arr = Array("background","language")

如何foldLeft /減少陣列和查找的字符串「英文「從地圖上。我嘗試這樣做:

arr.foldLeft(m) { (acc,x) => acc.get(x) }

但我得到這個錯誤:

<console>:10: error: type mismatch; 
found : Option[java.lang.Object] 
required: scala.collection.immutable.Map[java.lang.String,java.lang.Object] 
     arr.foldLeft(m) { (acc,x) => acc.get(x) } 
+0

不要有工作代碼,但這裏有一個提示:'M(「背景」)asInstanceOf [地圖[字符串,字符串]( 「語言」)'。 'm(「background」)'是一個'java.lang.Object',你需要額外的cast/match。然而,這個數據結構似乎有點奇怪,你應該考慮更多面向對象的東西。 –

回答

12

你要注意的類型。在這裏,你以你的acc開頭m : Map[String, Any]。您與字符串x結合並調用get,返回Option[Object]。要繼續,您必須檢查是否有值,檢查該值是否爲Map,cast(由於類型擦除而未選中,因此很危險)。

我相信錯在於你的結構類型Map [String,Any]代表你所擁有的很差。

假設你做的,而不是

sealed trait Tree 
case class Node(items: Map[String, Tree]) extends Tree 
case class Leaf(s: String) extends Tree 

您可以添加一些傭工作出聲明樹容易

object Tree { 
    implicit def fromString(s: String) = Leaf(s) 
    implicit def fromNamedString(nameAndValue: (String, String)) 
    = (nameAndValue._1, Leaf(nameAndValue._2)) 
} 
object Node { 
    def apply(items: (String, Tree)*) : Node = Node(Map(items: _*)) 
} 

然後聲明樹就像你的第一個版本一樣簡單,但類型是更精確

m = Node("email" -> "[email protected]", "background" -> Node("language" -> "english")) 

然後,您可以添加方法,例如在trait Tree

def get(path: String*) : Option[Tree] = { 
    if (path.isEmpty) Some(this) 
    else this match { 
     case Leaf(_) => None 
     case Node(map) => map.get(path.head).flatMap(_.get(path.tail: _*)) 
    } 
    } 
    def getLeaf(path: String*): Option[String] 
    = get(path: _*).collect{case Leaf(s) =>s} 

或者,如果你寧願用摺疊

def get(path: String*) = path.foldLeft[Option[Tree]](Some(this)) { 
    case (Some(Node(map)), p) => map.get(p) 
    case _ => None 
    } 
4

摺疊爲在嵌套映射的抽象做到這一點是不是真的支持。另外,你正在以一種防止類型系統給你很多幫助的方式來解決這個問題。但是,如果你堅持,那麼你想要一個遞歸函數:

def lookup(m: Map[String,Object], a: Array[String]): Option[String] = { 
    if (a.length == 0) None 
    else m.get(a(0)).flatMap(_ match { 
    case mm: Map[_,_] => lookup(mm.asInstanceOf[Map[String,Object]],a.tail) 
    case s: String if (a.length==1) => Some(s) 
    case _ => None 
    }) 
}